authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-09 10:20:58+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:11+00:00
log5865abf7f5ea2d4500cb8387252d9efee26ecae1
tree026c2a4150b8f5881ef70d52dc0fc99dd8efea6b
parent12ddd5a698577e22a0bb5ed788ea4b9729a45b5d
signaturelock-open Commit is signed but in an unrecognized format.

Sema: defer extern function type validation to declaration or call

Because of packed structs, checking whether a type is extern-compatible requires that its layout be resolved. For functions to do this validation as soon as the function type is created would lead to dependency loops in cases like '*const fn (*@This()) void callconv(.c)`. Therefore, when creating a function *type*, we no longer perform this check immediately, instead waiting until the function is called.

3 files changed, 156 insertions(+), 109 deletions(-)

src/Sema.zig+152-106
......@@ -5747,6 +5747,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
57475747 }
57485748
57495749 const export_ty = ptr_ty.childType(zcu);
5750 try sema.ensureLayoutResolved(export_ty, src, .@"export");
57505751 if (!export_ty.validateExtern(.other, zcu)) {
57515752 return sema.failWithOwnedErrorMsg(block, msg: {
57525753 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
......@@ -6749,6 +6750,37 @@ fn analyzeCall(
67496750 } else func_src;
67506751
67516752 const func_ty_info = zcu.typeToFunc(func_ty).?;
6753
6754 for (func_ty_info.param_types.get(ip), 0..) |param_ty_ip, param_index| {
6755 const arg_src = args_info.argSrc(block, param_index);
6756 try sema.ensureLayoutResolved(.fromInterned(param_ty_ip), arg_src, .init);
6757 }
6758 try sema.ensureLayoutResolved(.fromInterned(func_ty_info.return_type), func_ret_ty_src, .return_type);
6759 try sema.validateResolvedFuncType(
6760 block,
6761 func_ty_info.cc,
6762 func_ty_info.param_types.get(ip),
6763 .fromInterned(func_ty_info.return_type),
6764 func_src,
6765 maybe_func_inst,
6766 );
6767
6768 if (!callConvIsCallable(func_ty_info.cc)) {
6769 return sema.failWithOwnedErrorMsg(block, msg: {
6770 const msg = try sema.errMsg(
6771 func_src,
6772 "unable to call function with calling convention '{s}'",
6773 .{@tagName(func_ty_info.cc)},
6774 );
6775 errdefer msg.destroy(gpa);
6776 if (maybe_func_inst) |func_inst| try sema.errNote(.{
6777 .base_node_inst = func_inst,
6778 .offset = .nodeOffset(.zero),
6779 }, msg, "function declared here", .{});
6780 break :msg msg;
6781 });
6782 }
6783
67526784 const any_comptime_params = func_ty_info.comptime_bits != 0 or ct: {
67536785 for (func_ty_info.param_types.get(ip)) |param_ty| {
67546786 if (Type.fromInterned(param_ty).comptimeOnly(zcu)) break :ct true;
......@@ -6771,22 +6803,6 @@ fn analyzeCall(
67716803 break :generic false;
67726804 };
67736805
6774 if (!callConvIsCallable(func_ty_info.cc)) {
6775 return sema.failWithOwnedErrorMsg(block, msg: {
6776 const msg = try sema.errMsg(
6777 func_src,
6778 "unable to call function with calling convention '{s}'",
6779 .{@tagName(func_ty_info.cc)},
6780 );
6781 errdefer msg.destroy(gpa);
6782 if (maybe_func_inst) |func_inst| try sema.errNote(.{
6783 .base_node_inst = func_inst,
6784 .offset = .nodeOffset(.zero),
6785 }, msg, "function declared here", .{});
6786 break :msg msg;
6787 });
6788 }
6789
67906806 // We need this value in a few code paths.
67916807 const callee_val = try sema.resolveDefinedValue(block, call_src, callee);
67926808 // If the callee is a comptime-known *non-extern* function, `func_val` is populated.
......@@ -8755,11 +8771,12 @@ fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc:
87558771 }
87568772}
87578773
8758fn checkParamTypeCommon(
8774fn checkParamType(
87598775 sema: *Sema,
87608776 block: *Block,
87618777 param_idx: u32,
87628778 param_ty: Type,
8779 param_is_comptime: bool,
87638780 param_is_noalias: bool,
87648781 param_src: LazySrcLoc,
87658782 cc: std.builtin.CallingConvention,
......@@ -8774,29 +8791,22 @@ fn checkParamTypeCommon(
87748791 opaque_str, param_ty.fmt(pt),
87758792 });
87768793 }
8777 if (!param_ty.isGenericPoison() and
8778 !target_util.fnCallConvAllowsZigTypes(cc) and
8779 !param_ty.validateExtern(.param_ty, zcu))
8780 {
8781 return sema.failWithOwnedErrorMsg(block, msg: {
8782 const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{
8783 param_ty.fmt(pt), @tagName(cc),
8784 });
8785 errdefer msg.destroy(sema.gpa);
8786
8787 try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
8788
8789 try sema.addDeclaredHereNote(msg, param_ty);
8790 break :msg msg;
8791 });
8794 if (!target_util.fnCallConvAllowsZigTypes(cc)) {
8795 if (param_is_comptime) {
8796 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{t}'", .{cc});
8797 }
8798 if (param_ty.isGenericPoison()) {
8799 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{t}'", .{cc});
8800 }
8801 // The `validateExtern` check happens later, in `validateResolvedFuncType`.
87928802 }
87938803 switch (cc) {
87948804 .x86_64_interrupt, .x86_interrupt => {
87958805 const err_code_size = target.ptrBitWidth();
87968806 switch (param_idx) {
8797 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{s}' calling convention must be a pointer type", .{@tagName(cc)}),
8798 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{s}' calling convention must be a {d}-bit integer", .{ @tagName(cc), err_code_size }),
8799 else => return sema.fail(block, param_src, "'{s}' calling convention supports up to 2 parameters, found {d}", .{ @tagName(cc), param_idx + 1 }),
8807 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{t}' calling convention must be a pointer type", .{cc}),
8808 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{t}' calling convention must be a {d}-bit integer", .{ cc, err_code_size }),
8809 else => return sema.fail(block, param_src, "'{t}' calling convention supports up to 2 parameters, found {d}", .{ cc, param_idx + 1 }),
88008810 }
88018811 },
88028812 .arc_interrupt,
......@@ -8812,7 +8822,7 @@ fn checkParamTypeCommon(
88128822 .m68k_interrupt,
88138823 .msp430_interrupt,
88148824 .avr_signal,
8815 => return sema.fail(block, param_src, "parameters are not allowed with '{s}' calling convention", .{@tagName(cc)}),
8825 => return sema.fail(block, param_src, "parameters are not allowed with '{t}' calling convention", .{cc}),
88168826 else => {},
88178827 }
88188828 if (param_is_noalias and !param_ty.isGenericPoison() and !param_ty.isPtrAtRuntime(zcu) and !param_ty.isSliceAtRuntime(zcu)) {
......@@ -8820,7 +8830,7 @@ fn checkParamTypeCommon(
88208830 }
88218831}
88228832
8823fn checkReturnTypeAndCallConvCommon(
8833fn checkReturnTypeAndCallConv(
88248834 sema: *Sema,
88258835 block: *Block,
88268836 bare_ret_ty: Type,
......@@ -8834,7 +8844,6 @@ fn checkReturnTypeAndCallConvCommon(
88348844) CompileError!void {
88358845 const pt = sema.pt;
88368846 const zcu = pt.zcu;
8837 const gpa = zcu.gpa;
88388847 if (opt_varargs_src) |varargs_src| {
88398848 try sema.checkCallConvSupportsVarArgs(block, varargs_src, @"callconv");
88408849 }
......@@ -8848,21 +8857,14 @@ fn checkReturnTypeAndCallConvCommon(
88488857 opaque_str, ies_ret_ty_prefix, bare_ret_ty.fmt(pt),
88498858 });
88508859 }
8851 if (!bare_ret_ty.isGenericPoison() and
8852 !target_util.fnCallConvAllowsZigTypes(@"callconv") and
8853 (inferred_error_set or !bare_ret_ty.validateExtern(.ret_ty, zcu)))
8854 {
8855 return sema.failWithOwnedErrorMsg(block, msg: {
8856 const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{
8857 ies_ret_ty_prefix, bare_ret_ty.fmt(pt), @tagName(@"callconv"),
8858 });
8859 errdefer msg.destroy(gpa);
8860 if (!inferred_error_set) {
8861 try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, bare_ret_ty, .ret_ty);
8862 try sema.addDeclaredHereNote(msg, bare_ret_ty);
8863 }
8864 break :msg msg;
8865 });
8860 if (!target_util.fnCallConvAllowsZigTypes(@"callconv")) {
8861 if (inferred_error_set) {
8862 return sema.fail(block, ret_ty_src, "return type '!{f}' not allowed in function with calling convention '{t}'", .{ bare_ret_ty.fmt(pt), @"callconv" });
8863 }
8864 if (bare_ret_ty.isGenericPoison()) {
8865 return sema.fail(block, ret_ty_src, "generic return type not allowed in function with calling convention '{t}'", .{@"callconv"});
8866 }
8867 // The `validateExtern` check happens later, in `validateResolvedFuncType`.
88668868 }
88678869 validate_incoming_stack_align: {
88688870 const a: u64 = switch (@"callconv") {
......@@ -8897,7 +8899,7 @@ fn checkReturnTypeAndCallConvCommon(
88978899 else => false,
88988900 };
88998901 if (!ret_ok) {
8900 return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(@"callconv")});
8902 return sema.fail(block, ret_ty_src, "function with calling convention '{t}' must return 'void' or 'noreturn'", .{@"callconv"});
89018903 }
89028904 },
89038905 .@"inline" => if (is_noinline) {
......@@ -8918,18 +8920,76 @@ fn checkReturnTypeAndCallConvCommon(
89188920 }
89198921 }
89208922 };
8921 return sema.fail(block, callconv_src, "calling convention '{s}' only available on architectures {f}", .{
8922 @tagName(@"callconv"),
8923 ArchListFormatter{ .archs = allowed_archs },
8923 return sema.fail(block, callconv_src, "calling convention '{t}' only available on architectures {f}", .{
8924 @"callconv", ArchListFormatter{ .archs = allowed_archs },
89248925 });
89258926 },
8926 .bad_backend => |bad_backend| return sema.fail(block, callconv_src, "calling convention '{s}' not supported by compiler backend '{s}'", .{
8927 @tagName(@"callconv"),
8928 @tagName(bad_backend),
8927 .bad_backend => |bad_backend| return sema.fail(block, callconv_src, "calling convention '{t}' not supported by compiler backend '{t}'", .{
8928 @"callconv", bad_backend,
89298929 }),
89308930 }
89318931}
89328932
8933/// To avoid forcing type layout resolution too quickly, some validation of function types cannot be
8934/// performed when the type is first constructed, and instead must happen when either (a) a function
8935/// with that type is declared, or (b) a function with that type is called. That validation is
8936/// handled here.
8937///
8938/// Asserts that all parameter types and return types have their layout fully resolved.
8939fn validateResolvedFuncType(
8940 sema: *Sema,
8941 block: *Block,
8942 @"callconv": std.builtin.CallingConvention,
8943 param_types: []const InternPool.Index,
8944 ret_ty: Type,
8945 src: LazySrcLoc,
8946 maybe_func_decl_inst: ?InternPool.TrackedInst.Index,
8947) SemaError!void {
8948 const pt = sema.pt;
8949 const zcu = pt.zcu;
8950 const gpa = zcu.comp.gpa;
8951 if (!target_util.fnCallConvAllowsZigTypes(@"callconv")) {
8952 // Check that all parameter types are extern-compatible.
8953 for (param_types, 0..) |param_ty_ip, param_index| {
8954 const param_ty: Type = .fromInterned(param_ty_ip);
8955 if (!param_ty.validateExtern(.param_ty, zcu)) {
8956 const param_src: LazySrcLoc = if (maybe_func_decl_inst) |inst| .{
8957 .base_node_inst = inst,
8958 .offset = .{ .fn_proto_param = .{
8959 .fn_proto_node_offset = .zero,
8960 .param_index = @intCast(param_index),
8961 } },
8962 } else src;
8963 return sema.failWithOwnedErrorMsg(block, msg: {
8964 const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{t}'", .{
8965 param_ty.fmt(pt), @"callconv",
8966 });
8967 errdefer msg.destroy(gpa);
8968 try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
8969 try sema.addDeclaredHereNote(msg, param_ty);
8970 break :msg msg;
8971 });
8972 }
8973 }
8974 // Check that the return type is extern-compatible.
8975 if (!ret_ty.validateExtern(.ret_ty, zcu)) {
8976 const ret_ty_src: LazySrcLoc = if (maybe_func_decl_inst) |inst| .{
8977 .base_node_inst = inst,
8978 .offset = .{ .node_offset_fn_type_ret_ty = .zero },
8979 } else src;
8980 return sema.failWithOwnedErrorMsg(block, msg: {
8981 const msg = try sema.errMsg(ret_ty_src, "return type '{f}' not allowed in function with calling convention '{t}'", .{
8982 ret_ty.fmt(pt), @"callconv",
8983 });
8984 errdefer msg.destroy(gpa);
8985 try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, ret_ty, .ret_ty);
8986 try sema.addDeclaredHereNote(msg, ret_ty);
8987 break :msg msg;
8988 });
8989 }
8990 }
8991}
8992
89338993fn callConvIsCallable(cc: std.builtin.CallingConvention.Tag) bool {
89348994 return switch (cc) {
89358995 .naked,
......@@ -9022,6 +9082,7 @@ fn funcCommon(
90229082 const io = comp.io;
90239083 const ip = &zcu.intern_pool;
90249084
9085 const src = block.nodeOffset(src_node_offset);
90259086 const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });
90269087 const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });
90279088
......@@ -9036,27 +9097,21 @@ fn funcCommon(
90369097 .fn_proto_node_offset = src_node_offset,
90379098 .param_index = @intCast(i),
90389099 } });
9039 const param_ty_generic = param_ty.isGenericPoison();
90409100 if (param_is_comptime) {
90419101 comptime_bits |= @as(u32, 1) << @intCast(i); // TODO: handle cast error
90429102 }
9043 if (param_is_comptime and !target_util.fnCallConvAllowsZigTypes(cc)) {
9044 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
9045 }
9046 if (param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc)) {
9047 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
9048 }
9049 try sema.checkParamTypeCommon(
9103 try sema.checkParamType(
90509104 block,
90519105 @intCast(i),
90529106 param_ty,
9107 param_is_comptime,
90539108 is_noalias,
90549109 param_src,
90559110 cc,
90569111 );
90579112 }
90589113
9059 try sema.checkReturnTypeAndCallConvCommon(
9114 try sema.checkReturnTypeAndCallConv(
90609115 block,
90619116 bare_return_type,
90629117 ret_ty_src,
......@@ -9072,9 +9127,29 @@ fn funcCommon(
90729127
90739128 const param_types = block.params.items(.ty);
90749129
9130 if (has_body) {
9131 for (param_types, 0..) |param_ty_ip, param_index| {
9132 const param_ty: Type = .fromInterned(param_ty_ip);
9133 const param_src = block.src(.{ .fn_proto_param = .{
9134 .fn_proto_node_offset = src_node_offset,
9135 .param_index = @intCast(param_index),
9136 } });
9137 try sema.ensureLayoutResolved(param_ty, param_src, .parameter);
9138 }
9139 try sema.ensureLayoutResolved(bare_return_type, ret_ty_src, .return_type);
9140 try sema.validateResolvedFuncType(
9141 block,
9142 cc,
9143 param_types,
9144 bare_return_type,
9145 src,
9146 ip.getNav(sema.owner.unwrap().nav_val).srcInst(ip),
9147 );
9148 }
9149
90759150 if (inferred_error_set) {
90769151 assert(has_body);
9077 const func_val: Value = .fromInterned(try ip.getFuncDeclIes(gpa, io, pt.tid, .{
9152 return .fromIntern(try ip.getFuncDeclIes(gpa, io, pt.tid, .{
90789153 .owner_nav = sema.owner.unwrap().nav_val,
90799154
90809155 .param_types = param_types,
......@@ -9091,8 +9166,6 @@ fn funcCommon(
90919166 .lbrace_column = @as(u16, @truncate(src_locs.columns)),
90929167 .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
90939168 }));
9094 try sema.ensureLayoutResolved(func_val.typeOf(zcu), ret_ty_src, .return_type);
9095 return .fromValue(func_val);
90969169 }
90979170
90989171 const func_ty = try ip.getFuncType(gpa, io, pt.tid, .{
......@@ -9106,7 +9179,6 @@ fn funcCommon(
91069179 });
91079180
91089181 if (has_body) {
9109 try sema.ensureLayoutResolved(.fromInterned(func_ty), ret_ty_src, .return_type);
91109182 return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{
91119183 .owner_nav = sema.owner.unwrap().nav_val,
91129184 .ty = func_ty,
......@@ -18256,19 +18328,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1825618328 }
1825718329 } else if (inst_data.size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") {
1825818330 return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)});
18259 } else if (inst_data.size == .c) {
18260 if (!elem_ty.validateExtern(.other, zcu)) {
18261 const msg = msg: {
18262 const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
18263 errdefer msg.destroy(sema.gpa);
18264
18265 try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other);
18266
18267 try sema.addDeclaredHereNote(msg, elem_ty);
18268 break :msg msg;
18269 };
18270 return sema.failWithOwnedErrorMsg(block, msg);
18271 }
1827218331 }
1827318332
1827418333 if (host_size != 0) {
......@@ -19800,16 +19859,6 @@ fn zirReifyPointer(
1980019859 else => {},
1980119860 }
1980219861
19803 if (size == .c and !elem_ty.validateExtern(.other, zcu)) {
19804 return sema.failWithOwnedErrorMsg(block, msg: {
19805 const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
19806 errdefer msg.destroy(gpa);
19807 try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other);
19808 try sema.addDeclaredHereNote(msg, elem_ty);
19809 break :msg msg;
19810 });
19811 }
19812
1981319862 const sentinel_ty = try pt.optionalType(elem_ty.toIntern());
1981419863 const sentinel_uncoerced = sema.resolveInst(extra.sentinel);
1981519864 const sentinel_coerced = try sema.coerce(block, sentinel_ty, sentinel_uncoerced, sentinel_src);
......@@ -19898,10 +19947,11 @@ fn zirReifyFn(
1989819947 try param_attrs_arr.elemValue(pt, param_idx),
1989919948 std.builtin.Type.Fn.Param.Attributes,
1990019949 );
19901 try sema.checkParamTypeCommon(
19950 try sema.checkParamType(
1990219951 block,
1990319952 @intCast(param_idx),
1990419953 param_ty,
19954 false,
1990519955 param_attrs.@"noalias",
1990619956 param_types_src,
1990719957 fn_attrs.@"callconv",
......@@ -19919,7 +19969,7 @@ fn zirReifyFn(
1991919969 try sema.checkCallConvSupportsVarArgs(block, fn_attrs_src, fn_attrs.@"callconv");
1992019970 }
1992119971
19922 try sema.checkReturnTypeAndCallConvCommon(
19972 try sema.checkReturnTypeAndCallConv(
1992319973 block,
1992419974 ret_ty,
1992519975 ret_ty_src,
......@@ -19929,9 +19979,6 @@ fn zirReifyFn(
1992919979 false,
1993019980 false,
1993119981 );
19932 if (ret_ty.comptimeOnly(zcu)) {
19933 return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)});
19934 }
1993519982
1993619983 return .fromIntern(try ip.getFuncType(gpa, io, pt.tid, .{
1993719984 .param_types = param_types_ip,
......@@ -20615,7 +20662,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
2061520662
2061620663 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs);
2061720664 const arg_ty = try sema.resolveType(block, ty_src, extra.rhs);
20618
20665 try sema.ensureLayoutResolved(arg_ty, ty_src, .parameter);
2061920666 if (!arg_ty.validateExtern(.param_ty, sema.pt.zcu)) {
2062020667 const msg = msg: {
2062120668 const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)});
......@@ -24639,13 +24686,12 @@ fn zirBuiltinExtern(
2463924686 return sema.fail(block, ty_src, "expected (optional) pointer", .{});
2464024687 }
2464124688 if (!ty.validateExtern(.other, zcu)) {
24642 const msg = msg: {
24689 return sema.failWithOwnedErrorMsg(block, msg: {
2464324690 const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)});
2464424691 errdefer msg.destroy(sema.gpa);
2464524692 try sema.explainWhyTypeIsNotExtern(msg, ty_src, ty, .other);
2464624693 break :msg msg;
24647 };
24648 return sema.failWithOwnedErrorMsg(block, msg);
24694 });
2464924695 }
2465024696
2465124697 const options = try sema.resolveExternOptions(block, options_src, extra.rhs);
......@@ -25034,7 +25080,7 @@ pub fn explainWhyTypeIsNotExtern(
2503425080 src_loc: LazySrcLoc,
2503525081 ty: Type,
2503625082 position: Type.ExternPosition,
25037) CompileError!void {
25083) SemaError!void {
2503825084 const pt = sema.pt;
2503925085 const zcu = pt.zcu;
2504025086 switch (ty.zigTypeTag(zcu)) {
src/Sema/type_resolution.zig+2-2
......@@ -32,6 +32,7 @@ pub const LayoutResolveReason = enum {
3232 type_info,
3333 align_check,
3434 bit_ptr_child,
35 @"export",
3536 builtin_type,
3637
3738 /// Written after string: "while resolving type 'T' "
......@@ -56,6 +57,7 @@ pub const LayoutResolveReason = enum {
5657 .type_info => "for type information query here",
5758 .align_check => "for alignment check here",
5859 .bit_ptr_child => "for bit size check here",
60 .@"export" => "for export here",
5961 .builtin_type => "from 'std.builtin'",
6062 // zig fmt: on
6163 };
......@@ -276,7 +278,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
276278 assert(!field_ty.isGenericPoison());
277279 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
278280 try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
279
280281 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
281282 return sema.failWithOwnedErrorMsg(&block, msg: {
282283 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
......@@ -286,7 +287,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
286287 break :msg msg;
287288 });
288289 }
289
290290 if (struct_obj.layout == .@"extern" and !field_ty.validateExtern(.struct_field, zcu)) {
291291 return sema.failWithOwnedErrorMsg(&block, msg: {
292292 const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
src/Type.zig+2-1
......@@ -3055,9 +3055,10 @@ pub const ExternPosition = enum {
30553055};
30563056
30573057/// Returns true if `ty` is allowed in extern types.
3058/// Does not require `ty` to be resolved in any way.
3058/// Asserts that `ty` is fully resolved.
30593059/// Keep in sync with `Sema.explainWhyTypeIsNotExtern`.
30603060pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool {
3061 ty.assertHasLayout(zcu);
30613062 return switch (ty.zigTypeTag(zcu)) {
30623063 .type,
30633064 .comptime_float,