@@ -4740,12 +4740,19 @@ pub fn analyzeExport(
4740
4740
4741
4741
try mod.ensureDeclAnalyzed(exported_decl_index);
4742
4742
const exported_decl = mod.declPtr(exported_decl_index);
4743
- // TODO run the same checks as we do for C ABI struct fields
4744
- switch (exported_decl.ty.zigTypeTag()) {
4745
- .Fn, .Int, .Enum, .Struct, .Union, .Array, .Float, .Pointer, .Optional => {},
4746
- else => return sema.fail(block, src, "unable to export type '{}'", .{
4747
- exported_decl.ty.fmt(sema.mod),
4748
- }),
4743
+
4744
+ if (!(try sema.validateExternType(exported_decl.ty, .other))) {
4745
+ const msg = msg: {
4746
+ const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)});
4747
+ errdefer msg.destroy(sema.gpa);
4748
+
4749
+ const src_decl = sema.mod.declPtr(block.src_decl);
4750
+ try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), exported_decl.ty, .other);
4751
+
4752
+ try sema.addDeclaredHereNote(msg, exported_decl.ty);
4753
+ break :msg msg;
4754
+ };
4755
+ return sema.failWithOwnedErrorMsg(block, msg);
4749
4756
}
4750
4757
4751
4758
const gpa = mod.gpa;
@@ -13799,7 +13806,20 @@ fn validatePtrTy(sema: *Sema, block: *Block, elem_src: LazySrcLoc, ty: Type) Com
13799
13806
} else if (ptr_info.size == .Many and pointee_tag == .Opaque) {
13800
13807
return sema.fail(block, elem_src, "unknown-length pointer to opaque not allowed", .{});
13801
13808
} else if (ptr_info.size == .C) {
13802
- // TODO check extern type
13809
+ const elem_ty = ptr_info.pointee_type;
13810
+ if (!(try sema.validateExternType(elem_ty, .other))) {
13811
+ const msg = msg: {
13812
+ const msg = try sema.errMsg(block, elem_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
13813
+ errdefer msg.destroy(sema.gpa);
13814
+
13815
+ const src_decl = sema.mod.declPtr(block.src_decl);
13816
+ try sema.explainWhyTypeIsNotExtern(block, elem_src, msg, elem_src.toSrcLoc(src_decl), elem_ty, .other);
13817
+
13818
+ try sema.addDeclaredHereNote(msg, elem_ty);
13819
+ break :msg msg;
13820
+ };
13821
+ return sema.failWithOwnedErrorMsg(block, msg);
13822
+ }
13803
13823
if (pointee_tag == .Opaque) {
13804
13824
return sema.fail(block, elem_src, "C pointers cannot point to opaque types", .{});
13805
13825
}
@@ -18098,10 +18118,12 @@ fn explainWhyTypeIsComptime(
18098
18118
.NoReturn,
18099
18119
.Undefined,
18100
18120
.Null,
18101
- .Opaque,
18102
- .Optional,
18103
18121
=> return,
18104
18122
18123
+ .Opaque => {
18124
+ try mod.errNoteNonLazy(src_loc, msg, "opaque type '{}' has undefined size", .{ty.fmt(sema.mod)});
18125
+ },
18126
+
18105
18127
.Array, .Vector => {
18106
18128
try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());
18107
18129
},
@@ -18124,6 +18146,10 @@ fn explainWhyTypeIsComptime(
18124
18146
try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());
18125
18147
},
18126
18148
18149
+ .Optional => {
18150
+ var buf: Type.Payload.ElemType = undefined;
18151
+ try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.optionalChild(&buf));
18152
+ },
18127
18153
.ErrorUnion => {
18128
18154
try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.errorUnionPayload());
18129
18155
},
@@ -18163,6 +18189,120 @@ fn explainWhyTypeIsComptime(
18163
18189
}
18164
18190
}
18165
18191
18192
+ const ExternPosition = enum {
18193
+ ret_ty,
18194
+ param_ty,
18195
+ union_field,
18196
+ other,
18197
+ };
18198
+
18199
+ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) CompileError!bool {
18200
+ switch (ty.zigTypeTag()) {
18201
+ .Type,
18202
+ .ComptimeFloat,
18203
+ .ComptimeInt,
18204
+ .EnumLiteral,
18205
+ .Undefined,
18206
+ .Null,
18207
+ .ErrorUnion,
18208
+ .ErrorSet,
18209
+ .BoundFn,
18210
+ .Frame,
18211
+ => return false,
18212
+ .Void => return position == .union_field,
18213
+ .NoReturn => return position == .ret_ty,
18214
+ .Opaque,
18215
+ .Bool,
18216
+ .Float,
18217
+ .Pointer,
18218
+ .AnyFrame,
18219
+ => return true,
18220
+ .Int => switch (ty.intInfo(sema.mod.getTarget()).bits) {
18221
+ 8, 16, 32, 64, 128 => return true,
18222
+ else => return false,
18223
+ },
18224
+ .Fn => return !ty.fnCallingConventionAllowsZigTypes(),
18225
+ .Enum => {
18226
+ var buf: Type.Payload.Bits = undefined;
18227
+ return sema.validateExternType(ty.intTagType(&buf), position);
18228
+ },
18229
+ .Struct, .Union => switch (ty.containerLayout()) {
18230
+ .Extern, .Packed => return true,
18231
+ else => return false,
18232
+ },
18233
+ .Array => {
18234
+ if (position == .ret_ty or position == .param_ty) return false;
18235
+ return sema.validateExternType(ty.elemType2(), .other);
18236
+ },
18237
+ .Vector => return sema.validateExternType(ty.elemType2(), .other),
18238
+ .Optional => return ty.isPtrLikeOptional(),
18239
+ }
18240
+ }
18241
+
18242
+ fn explainWhyTypeIsNotExtern(
18243
+ sema: *Sema,
18244
+ block: *Block,
18245
+ src: LazySrcLoc,
18246
+ msg: *Module.ErrorMsg,
18247
+ src_loc: Module.SrcLoc,
18248
+ ty: Type,
18249
+ position: ExternPosition,
18250
+ ) CompileError!void {
18251
+ const mod = sema.mod;
18252
+ switch (ty.zigTypeTag()) {
18253
+ .Opaque,
18254
+ .Bool,
18255
+ .Float,
18256
+ .Pointer,
18257
+ .AnyFrame,
18258
+ => return,
18259
+
18260
+ .Type,
18261
+ .ComptimeFloat,
18262
+ .ComptimeInt,
18263
+ .EnumLiteral,
18264
+ .Undefined,
18265
+ .Null,
18266
+ .ErrorUnion,
18267
+ .ErrorSet,
18268
+ .BoundFn,
18269
+ .Frame,
18270
+ => return,
18271
+
18272
+ .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
18273
+ .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
18274
+ .Int => if (ty.intInfo(sema.mod.getTarget()).bits > 128) {
18275
+ try mod.errNoteNonLazy(src_loc, msg, "only integers with less than 128 bits are extern compatible", .{});
18276
+ } else {
18277
+ try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});
18278
+ },
18279
+ .Fn => switch (ty.fnCallingConvention()) {
18280
+ .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}),
18281
+ .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}),
18282
+ .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}),
18283
+ else => return,
18284
+ },
18285
+ .Enum => {
18286
+ var buf: Type.Payload.Bits = undefined;
18287
+ const tag_ty = ty.intTagType(&buf);
18288
+ try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)});
18289
+ try sema.explainWhyTypeIsNotExtern(block, src, msg, src_loc, tag_ty, position);
18290
+ },
18291
+ .Struct => try mod.errNoteNonLazy(src_loc, msg, "only structs with packed or extern layout are extern compatible", .{}),
18292
+ .Union => try mod.errNoteNonLazy(src_loc, msg, "only unions with packed or extern layout are extern compatible", .{}),
18293
+ .Array => {
18294
+ if (position == .ret_ty) {
18295
+ try mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{});
18296
+ } else if (position == .param_ty) {
18297
+ try mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{});
18298
+ }
18299
+ try sema.explainWhyTypeIsNotExtern(block, src, msg, src_loc, ty.elemType2(), position);
18300
+ },
18301
+ .Vector => try sema.explainWhyTypeIsNotExtern(block, src, msg, src_loc, ty.elemType2(), position),
18302
+ .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
18303
+ }
18304
+ }
18305
+
18166
18306
pub const PanicId = enum {
18167
18307
unreach,
18168
18308
unwrap_null,
@@ -24006,6 +24146,20 @@ fn resolveStructFully(
24006
24146
struct_obj.status = .fully_resolved_wip;
24007
24147
for (struct_obj.fields.values()) |field| {
24008
24148
try sema.resolveTypeFully(block, src, field.ty);
24149
+
24150
+ if (struct_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .other))) {
24151
+ const msg = msg: {
24152
+ const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
24153
+ errdefer msg.destroy(sema.gpa);
24154
+
24155
+ const src_decl = sema.mod.declPtr(block.src_decl);
24156
+ try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), field.ty, .other);
24157
+
24158
+ try sema.addDeclaredHereNote(msg, field.ty);
24159
+ break :msg msg;
24160
+ };
24161
+ return sema.failWithOwnedErrorMsg(block, msg);
24162
+ }
24009
24163
}
24010
24164
struct_obj.status = .fully_resolved;
24011
24165
}
@@ -24039,6 +24193,20 @@ fn resolveUnionFully(
24039
24193
union_obj.status = .fully_resolved_wip;
24040
24194
for (union_obj.fields.values()) |field| {
24041
24195
try sema.resolveTypeFully(block, src, field.ty);
24196
+
24197
+ if (union_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .union_field))) {
24198
+ const msg = msg: {
24199
+ const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
24200
+ errdefer msg.destroy(sema.gpa);
24201
+
24202
+ const src_decl = sema.mod.declPtr(block.src_decl);
24203
+ try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), field.ty, .union_field);
24204
+
24205
+ try sema.addDeclaredHereNote(msg, field.ty);
24206
+ break :msg msg;
24207
+ };
24208
+ return sema.failWithOwnedErrorMsg(block, msg);
24209
+ }
24042
24210
}
24043
24211
union_obj.status = .fully_resolved;
24044
24212
}
0 commit comments