| author | |
| committer | |
| log | d851b24180fdf2b622b06e9a35e315541fb10aa1 |
| tree | 3502677e69ee19a43104e8b5008e968bd0365a24 |
| parent | 76e7959a90ae025a1934a4ad1c689663f523a4bc |
7 files changed, 148 insertions(+), 19 deletions(-)
src/Module.zig+87-1| ... | ... | @@ -2348,7 +2348,72 @@ pub const SrcLoc = struct { |
| 2348 | 2348 | } |
| 2349 | 2349 | } else unreachable; |
| 2350 | 2350 | }, |
| 2351 | ||
| 2351 | .node_offset_fn_type_align => |node_off| { | |
| 2352 | const tree = try src_loc.file_scope.getTree(gpa); | |
| 2353 | const node_datas = tree.nodes.items(.data); | |
| 2354 | const node_tags = tree.nodes.items(.tag); | |
| 2355 | const node = src_loc.declRelativeToNodeIndex(node_off); | |
| 2356 | var params: [1]Ast.Node.Index = undefined; | |
| 2357 | const full = switch (node_tags[node]) { | |
| 2358 | .fn_proto_simple => tree.fnProtoSimple(&params, node), | |
| 2359 | .fn_proto_multi => tree.fnProtoMulti(node), | |
| 2360 | .fn_proto_one => tree.fnProtoOne(&params, node), | |
| 2361 | .fn_proto => tree.fnProto(node), | |
| 2362 | .fn_decl => switch (node_tags[node_datas[node].lhs]) { | |
| 2363 | .fn_proto_simple => tree.fnProtoSimple(&params, node_datas[node].lhs), | |
| 2364 | .fn_proto_multi => tree.fnProtoMulti(node_datas[node].lhs), | |
| 2365 | .fn_proto_one => tree.fnProtoOne(&params, node_datas[node].lhs), | |
| 2366 | .fn_proto => tree.fnProto(node_datas[node].lhs), | |
| 2367 | else => unreachable, | |
| 2368 | }, | |
| 2369 | else => unreachable, | |
| 2370 | }; | |
| 2371 | return nodeToSpan(tree, full.ast.align_expr); | |
| 2372 | }, | |
| 2373 | .node_offset_fn_type_addrspace => |node_off| { | |
| 2374 | const tree = try src_loc.file_scope.getTree(gpa); | |
| 2375 | const node_datas = tree.nodes.items(.data); | |
| 2376 | const node_tags = tree.nodes.items(.tag); | |
| 2377 | const node = src_loc.declRelativeToNodeIndex(node_off); | |
| 2378 | var params: [1]Ast.Node.Index = undefined; | |
| 2379 | const full = switch (node_tags[node]) { | |
| 2380 | .fn_proto_simple => tree.fnProtoSimple(&params, node), | |
| 2381 | .fn_proto_multi => tree.fnProtoMulti(node), | |
| 2382 | .fn_proto_one => tree.fnProtoOne(&params, node), | |
| 2383 | .fn_proto => tree.fnProto(node), | |
| 2384 | .fn_decl => switch (node_tags[node_datas[node].lhs]) { | |
| 2385 | .fn_proto_simple => tree.fnProtoSimple(&params, node_datas[node].lhs), | |
| 2386 | .fn_proto_multi => tree.fnProtoMulti(node_datas[node].lhs), | |
| 2387 | .fn_proto_one => tree.fnProtoOne(&params, node_datas[node].lhs), | |
| 2388 | .fn_proto => tree.fnProto(node_datas[node].lhs), | |
| 2389 | else => unreachable, | |
| 2390 | }, | |
| 2391 | else => unreachable, | |
| 2392 | }; | |
| 2393 | return nodeToSpan(tree, full.ast.addrspace_expr); | |
| 2394 | }, | |
| 2395 | .node_offset_fn_type_section => |node_off| { | |
| 2396 | const tree = try src_loc.file_scope.getTree(gpa); | |
| 2397 | const node_datas = tree.nodes.items(.data); | |
| 2398 | const node_tags = tree.nodes.items(.tag); | |
| 2399 | const node = src_loc.declRelativeToNodeIndex(node_off); | |
| 2400 | var params: [1]Ast.Node.Index = undefined; | |
| 2401 | const full = switch (node_tags[node]) { | |
| 2402 | .fn_proto_simple => tree.fnProtoSimple(&params, node), | |
| 2403 | .fn_proto_multi => tree.fnProtoMulti(node), | |
| 2404 | .fn_proto_one => tree.fnProtoOne(&params, node), | |
| 2405 | .fn_proto => tree.fnProto(node), | |
| 2406 | .fn_decl => switch (node_tags[node_datas[node].lhs]) { | |
| 2407 | .fn_proto_simple => tree.fnProtoSimple(&params, node_datas[node].lhs), | |
| 2408 | .fn_proto_multi => tree.fnProtoMulti(node_datas[node].lhs), | |
| 2409 | .fn_proto_one => tree.fnProtoOne(&params, node_datas[node].lhs), | |
| 2410 | .fn_proto => tree.fnProto(node_datas[node].lhs), | |
| 2411 | else => unreachable, | |
| 2412 | }, | |
| 2413 | else => unreachable, | |
| 2414 | }; | |
| 2415 | return nodeToSpan(tree, full.ast.section_expr); | |
| 2416 | }, | |
| 2352 | 2417 | .node_offset_fn_type_cc => |node_off| { |
| 2353 | 2418 | const tree = try src_loc.file_scope.getTree(gpa); |
| 2354 | 2419 | const node_datas = tree.nodes.items(.data); |
| ... | ... | @@ -2778,6 +2843,24 @@ pub const LazySrcLoc = union(enum) { |
| 2778 | 2843 | /// range nodes. The error applies to all of them. |
| 2779 | 2844 | /// The Decl is determined contextually. |
| 2780 | 2845 | node_offset_switch_range: i32, |
| 2846 | /// The source location points to the align expr of a function type | |
| 2847 | /// expression, found by taking this AST node index offset from the containing | |
| 2848 | /// Decl AST node, which points to a function type AST node. Next, navigate to | |
| 2849 | /// the calling convention node. | |
| 2850 | /// The Decl is determined contextually. | |
| 2851 | node_offset_fn_type_align: i32, | |
| 2852 | /// The source location points to the addrspace expr of a function type | |
| 2853 | /// expression, found by taking this AST node index offset from the containing | |
| 2854 | /// Decl AST node, which points to a function type AST node. Next, navigate to | |
| 2855 | /// the calling convention node. | |
| 2856 | /// The Decl is determined contextually. | |
| 2857 | node_offset_fn_type_addrspace: i32, | |
| 2858 | /// The source location points to the linksection expr of a function type | |
| 2859 | /// expression, found by taking this AST node index offset from the containing | |
| 2860 | /// Decl AST node, which points to a function type AST node. Next, navigate to | |
| 2861 | /// the calling convention node. | |
| 2862 | /// The Decl is determined contextually. | |
| 2863 | node_offset_fn_type_section: i32, | |
| 2781 | 2864 | /// The source location points to the calling convention of a function type |
| 2782 | 2865 | /// expression, found by taking this AST node index offset from the containing |
| 2783 | 2866 | /// Decl AST node, which points to a function type AST node. Next, navigate to |
| ... | ... | @@ -2897,6 +2980,9 @@ pub const LazySrcLoc = union(enum) { |
| 2897 | 2980 | .node_offset_switch_operand, |
| 2898 | 2981 | .node_offset_switch_special_prong, |
| 2899 | 2982 | .node_offset_switch_range, |
| 2983 | .node_offset_fn_type_align, | |
| 2984 | .node_offset_fn_type_addrspace, | |
| 2985 | .node_offset_fn_type_section, | |
| 2900 | 2986 | .node_offset_fn_type_cc, |
| 2901 | 2987 | .node_offset_fn_type_ret_ty, |
| 2902 | 2988 | .node_offset_anyframe_type, |
src/Sema.zig+27-8| ... | ... | @@ -1884,13 +1884,22 @@ fn analyzeAsAlign( |
| 1884 | 1884 | ) !u32 { |
| 1885 | 1885 | const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, "alignment must be comptime known"); |
| 1886 | 1886 | const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line. |
| 1887 | try sema.validateAlign(block, src, alignment); | |
| 1888 | return alignment; | |
| 1889 | } | |
| 1890 | ||
| 1891 | fn validateAlign( | |
| 1892 | sema: *Sema, | |
| 1893 | block: *Block, | |
| 1894 | src: LazySrcLoc, | |
| 1895 | alignment: u32, | |
| 1896 | ) !void { | |
| 1887 | 1897 | if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{}); |
| 1888 | 1898 | if (!std.math.isPowerOfTwo(alignment)) { |
| 1889 | 1899 | return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{ |
| 1890 | 1900 | alignment, |
| 1891 | 1901 | }); |
| 1892 | 1902 | } |
| 1893 | return alignment; | |
| 1894 | 1903 | } |
| 1895 | 1904 | |
| 1896 | 1905 | pub fn resolveAlign( |
| ... | ... | @@ -13902,8 +13911,9 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 13902 | 13911 | break :blk 0; |
| 13903 | 13912 | } |
| 13904 | 13913 | } |
| 13905 | const abi_align = (try val.getUnsignedIntAdvanced(target, sema.kit(block, align_src))).?; | |
| 13906 | break :blk @intCast(u32, abi_align); | |
| 13914 | const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(target, sema.kit(block, align_src))).?); | |
| 13915 | try sema.validateAlign(block, align_src, abi_align); | |
| 13916 | break :blk abi_align; | |
| 13907 | 13917 | } else 0; |
| 13908 | 13918 | |
| 13909 | 13919 | const address_space = if (inst_data.flags.has_addrspace) blk: { |
| ... | ... | @@ -13940,6 +13950,14 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 13940 | 13950 | |
| 13941 | 13951 | if (elem_ty.zigTypeTag() == .NoReturn) { |
| 13942 | 13952 | return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); |
| 13953 | } else if (elem_ty.zigTypeTag() == .Fn) { | |
| 13954 | if (inst_data.size != .One) { | |
| 13955 | return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); | |
| 13956 | } | |
| 13957 | const fn_align = elem_ty.abiAlignment(target); | |
| 13958 | if (inst_data.flags.has_align and abi_align != 0 and abi_align != fn_align) { | |
| 13959 | return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{}); | |
| 13960 | } | |
| 13943 | 13961 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) { |
| 13944 | 13962 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); |
| 13945 | 13963 | } else if (inst_data.size == .C) { |
| ... | ... | @@ -17709,15 +17727,14 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 17709 | 17727 | defer tracy.end(); |
| 17710 | 17728 | |
| 17711 | 17729 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 17712 | const src = inst_data.src(); | |
| 17713 | 17730 | const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index); |
| 17714 | 17731 | const target = sema.mod.getTarget(); |
| 17715 | 17732 | |
| 17716 | const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align | |
| 17717 | const addrspace_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at addrspace | |
| 17718 | const section_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at section | |
| 17733 | const align_src: LazySrcLoc = .{ .node_offset_fn_type_align = inst_data.src_node }; | |
| 17734 | const addrspace_src: LazySrcLoc = .{ .node_offset_fn_type_addrspace = inst_data.src_node }; | |
| 17735 | const section_src: LazySrcLoc = .{ .node_offset_fn_type_section = inst_data.src_node }; | |
| 17719 | 17736 | const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node }; |
| 17720 | const ret_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at the return type | |
| 17737 | const ret_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node }; | |
| 17721 | 17738 | |
| 17722 | 17739 | var extra_index: usize = extra.end; |
| 17723 | 17740 | |
| ... | ... | @@ -17742,6 +17759,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 17742 | 17759 | break :blk null; |
| 17743 | 17760 | } |
| 17744 | 17761 | const alignment = @intCast(u32, val.toUnsignedInt(target)); |
| 17762 | try sema.validateAlign(block, align_src, alignment); | |
| 17745 | 17763 | if (alignment == target_util.defaultFunctionAlignment(target)) { |
| 17746 | 17764 | break :blk 0; |
| 17747 | 17765 | } else { |
| ... | ... | @@ -17757,6 +17775,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 17757 | 17775 | else => |e| return e, |
| 17758 | 17776 | }; |
| 17759 | 17777 | const alignment = @intCast(u32, align_tv.val.toUnsignedInt(target)); |
| 17778 | try sema.validateAlign(block, align_src, alignment); | |
| 17760 | 17779 | if (alignment == target_util.defaultFunctionAlignment(target)) { |
| 17761 | 17780 | break :blk 0; |
| 17762 | 17781 | } else { |
test/behavior/align.zig-1| ... | ... | @@ -299,7 +299,6 @@ test "implicitly decreasing fn alignment" { |
| 299 | 299 | try testImplicitlyDecreaseFnAlign(alignedBig, 5678); |
| 300 | 300 | } |
| 301 | 301 | |
| 302 | // TODO make it a compile error to put align on the fn proto instead of on the ptr | |
| 303 | 302 | fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void { |
| 304 | 303 | try expect(ptr() == answer); |
| 305 | 304 | } |
test/cases/compile_errors/align_n_expr_function_pointers_is_a_compile_error.zig+1-1| ... | ... | @@ -6,4 +6,4 @@ export fn foo() align(1) void { |
| 6 | 6 | // backend=stage2 |
| 7 | 7 | // target=wasm32-freestanding-none |
| 8 | 8 | // |
| 9 | // :1:8: error: 'align' is not allowed on functions in wasm | |
| 9 | // :1:23: error: 'align' is not allowed on functions in wasm | |
| \ No newline at end of file |
test/cases/compile_errors/function_alignment_non_power_of_2.zig created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | extern fn foo() align(3) void; | |
| 2 | export fn entry() void { return foo(); } | |
| 3 | ||
| 4 | // error | |
| 5 | // backend=stage2 | |
| 6 | // target=native | |
| 7 | // | |
| 8 | // :1:23: error: alignment value '3' is not a power of two |
test/cases/compile_errors/function_ptr_alignment.zig created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | comptime { | |
| 2 | var a: *align(2) @TypeOf(foo) = undefined; | |
| 3 | _ = a; | |
| 4 | } | |
| 5 | fn foo() void {} | |
| 6 | ||
| 7 | comptime { | |
| 8 | var a: *align(1) fn () void = undefined; | |
| 9 | _ = a; | |
| 10 | } | |
| 11 | comptime { | |
| 12 | var a: *align(2) fn () align(2) void = undefined; | |
| 13 | _ = a; | |
| 14 | } | |
| 15 | comptime { | |
| 16 | var a: *align(2) fn () void = undefined; | |
| 17 | _ = a; | |
| 18 | } | |
| 19 | ||
| 20 | // error | |
| 21 | // backend=stage2 | |
| 22 | // target=native | |
| 23 | // | |
| 24 | // :2:19: error: function pointer alignment disagrees with function alignment | |
| 25 | // :16:19: error: function pointer alignment disagrees with function alignment |
test/cases/compile_errors/stage1/obj/function_alignment_non_power_of_2.zig deleted-8| ... | ... | @@ -1,8 +0,0 @@ |
| 1 | extern fn foo() align(3) void; | |
| 2 | export fn entry() void { return foo(); } | |
| 3 | ||
| 4 | // error | |
| 5 | // backend=stage1 | |
| 6 | // target=native | |
| 7 | // | |
| 8 | // tmp.zig:1:23: error: alignment value 3 is not a power of 2 |