@@ -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
}
@@ -18169,6 +18189,119 @@ fn explainWhyTypeIsComptime(
18169
18189
}
18170
18190
}
18171
18191
18192
+ const ExternPosition = enum {
18193
+ ret_ty,
18194
+ param_ty,
18195
+ other,
18196
+ };
18197
+
18198
+ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) CompileError!bool {
18199
+ switch (ty.zigTypeTag()) {
18200
+ .Type,
18201
+ .ComptimeFloat,
18202
+ .ComptimeInt,
18203
+ .EnumLiteral,
18204
+ .Undefined,
18205
+ .Null,
18206
+ .ErrorUnion,
18207
+ .ErrorSet,
18208
+ .BoundFn,
18209
+ .Void,
18210
+ .Frame,
18211
+ => return false,
18212
+ .NoReturn => return position == .ret_ty,
18213
+ .Opaque,
18214
+ .Bool,
18215
+ .Float,
18216
+ .Pointer,
18217
+ .AnyFrame,
18218
+ => return true,
18219
+ .Int => switch (ty.intInfo(sema.mod.getTarget()).bits) {
18220
+ 8, 16, 32, 64, 128 => return true,
18221
+ else => return false,
18222
+ },
18223
+ .Fn => return !ty.fnCallingConventionAllowsZigTypes(),
18224
+ .Enum => {
18225
+ var buf: Type.Payload.Bits = undefined;
18226
+ return sema.validateExternType(ty.intTagType(&buf), position);
18227
+ },
18228
+ .Struct, .Union => switch (ty.containerLayout()) {
18229
+ .Extern, .Packed => return true,
18230
+ else => return false,
18231
+ },
18232
+ .Array => {
18233
+ if (position == .ret_ty or position == .param_ty) return false;
18234
+ return sema.validateExternType(ty.elemType2(), .other);
18235
+ },
18236
+ .Vector => return sema.validateExternType(ty.elemType2(), .other),
18237
+ .Optional => return ty.isPtrLikeOptional(),
18238
+ }
18239
+ }
18240
+
18241
+ fn explainWhyTypeIsNotExtern(
18242
+ sema: *Sema,
18243
+ block: *Block,
18244
+ src: LazySrcLoc,
18245
+ msg: *Module.ErrorMsg,
18246
+ src_loc: Module.SrcLoc,
18247
+ ty: Type,
18248
+ position: ExternPosition,
18249
+ ) CompileError!void {
18250
+ const mod = sema.mod;
18251
+ switch (ty.zigTypeTag()) {
18252
+ .Opaque,
18253
+ .Bool,
18254
+ .Float,
18255
+ .Pointer,
18256
+ .AnyFrame,
18257
+ => return,
18258
+
18259
+ .Type,
18260
+ .ComptimeFloat,
18261
+ .ComptimeInt,
18262
+ .EnumLiteral,
18263
+ .Undefined,
18264
+ .Null,
18265
+ .ErrorUnion,
18266
+ .ErrorSet,
18267
+ .BoundFn,
18268
+ .Frame,
18269
+ => return,
18270
+
18271
+ .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
18272
+ .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
18273
+ .Int => if (ty.intInfo(sema.mod.getTarget()).bits > 128) {
18274
+ try mod.errNoteNonLazy(src_loc, msg, "only integers with less than 128 bits are extern compatible", .{});
18275
+ } else {
18276
+ try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});
18277
+ },
18278
+ .Fn => switch (ty.fnCallingConvention()) {
18279
+ .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}),
18280
+ .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}),
18281
+ .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}),
18282
+ else => return,
18283
+ },
18284
+ .Enum => {
18285
+ var buf: Type.Payload.Bits = undefined;
18286
+ const tag_ty = ty.intTagType(&buf);
18287
+ try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)});
18288
+ try sema.explainWhyTypeIsNotExtern(block, src, msg, src_loc, tag_ty, position);
18289
+ },
18290
+ .Struct => try mod.errNoteNonLazy(src_loc, msg, "only structs with packed or extern layout are extern compatible", .{}),
18291
+ .Union => try mod.errNoteNonLazy(src_loc, msg, "only unions with packed or extern layout are extern compatible", .{}),
18292
+ .Array => {
18293
+ if (position == .ret_ty) {
18294
+ try mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{});
18295
+ } else if (position == .param_ty) {
18296
+ try mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{});
18297
+ }
18298
+ try sema.explainWhyTypeIsNotExtern(block, src, msg, src_loc, ty.elemType2(), position);
18299
+ },
18300
+ .Vector => try sema.explainWhyTypeIsNotExtern(block, src, msg, src_loc, ty.elemType2(), position),
18301
+ .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
18302
+ }
18303
+ }
18304
+
18172
18305
pub const PanicId = enum {
18173
18306
unreach,
18174
18307
unwrap_null,
@@ -24012,6 +24145,20 @@ fn resolveStructFully(
24012
24145
struct_obj.status = .fully_resolved_wip;
24013
24146
for (struct_obj.fields.values()) |field| {
24014
24147
try sema.resolveTypeFully(block, src, field.ty);
24148
+
24149
+ if (struct_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .other))) {
24150
+ const msg = msg: {
24151
+ const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
24152
+ errdefer msg.destroy(sema.gpa);
24153
+
24154
+ const src_decl = sema.mod.declPtr(block.src_decl);
24155
+ try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), field.ty, .other);
24156
+
24157
+ try sema.addDeclaredHereNote(msg, field.ty);
24158
+ break :msg msg;
24159
+ };
24160
+ return sema.failWithOwnedErrorMsg(block, msg);
24161
+ }
24015
24162
}
24016
24163
struct_obj.status = .fully_resolved;
24017
24164
}
@@ -24045,6 +24192,20 @@ fn resolveUnionFully(
24045
24192
union_obj.status = .fully_resolved_wip;
24046
24193
for (union_obj.fields.values()) |field| {
24047
24194
try sema.resolveTypeFully(block, src, field.ty);
24195
+
24196
+ if (union_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .other))) {
24197
+ const msg = msg: {
24198
+ const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
24199
+ errdefer msg.destroy(sema.gpa);
24200
+
24201
+ const src_decl = sema.mod.declPtr(block.src_decl);
24202
+ try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), field.ty, .other);
24203
+
24204
+ try sema.addDeclaredHereNote(msg, field.ty);
24205
+ break :msg msg;
24206
+ };
24207
+ return sema.failWithOwnedErrorMsg(block, msg);
24208
+ }
24048
24209
}
24049
24210
union_obj.status = .fully_resolved;
24050
24211
}
0 commit comments