authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-06 15:00:52+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-06 20:09:45+03:00
logdffce980451379e0a829e130cd09e2c934b75e28
tree22ac914bce930a9c26cb33e7d911aca34b58c717
parent446deb31a80a2bd046633fb087d8caee3ed41021

Sema: disallow using stage1 fn ptrs in extern contexts

Closes #13022

2 files changed, 46 insertions(+), 14 deletions(-)

src/Sema.zig+26-14
...@@ -21232,6 +21232,8 @@ const ExternPosition = enum {...@@ -21232,6 +21232,8 @@ const ExternPosition = enum {
21232 ret_ty,21232 ret_ty,
21233 param_ty,21233 param_ty,
21234 union_field,21234 union_field,
21235 struct_field,
21236 element,
21235 other,21237 other,
21236};21238};
2123721239
...@@ -21269,7 +21271,10 @@ fn validateExternType(...@@ -21269,7 +21271,10 @@ fn validateExternType(
21269 8, 16, 32, 64, 128 => return true,21271 8, 16, 32, 64, 128 => return true,
21270 else => return false,21272 else => return false,
21271 },21273 },
21272 .Fn => return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()),21274 .Fn => {
21275 if (position != .other) return false;
21276 return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention());
21277 },
21273 .Enum => {21278 .Enum => {
21274 var buf: Type.Payload.Bits = undefined;21279 var buf: Type.Payload.Bits = undefined;
21275 return sema.validateExternType(block, src, ty.intTagType(&buf), position);21280 return sema.validateExternType(block, src, ty.intTagType(&buf), position);
...@@ -21288,9 +21293,9 @@ fn validateExternType(...@@ -21288,9 +21293,9 @@ fn validateExternType(
21288 },21293 },
21289 .Array => {21294 .Array => {
21290 if (position == .ret_ty or position == .param_ty) return false;21295 if (position == .ret_ty or position == .param_ty) return false;
21291 return sema.validateExternType(block, src, ty.elemType2(), .other);21296 return sema.validateExternType(block, src, ty.elemType2(), .element);
21292 },21297 },
21293 .Vector => return sema.validateExternType(block, src, ty.elemType2(), .other),21298 .Vector => return sema.validateExternType(block, src, ty.elemType2(), .element),
21294 .Optional => return ty.isPtrLikeOptional(),21299 .Optional => return ty.isPtrLikeOptional(),
21295 }21300 }
21296}21301}
...@@ -21330,11 +21335,18 @@ fn explainWhyTypeIsNotExtern(...@@ -21330,11 +21335,18 @@ fn explainWhyTypeIsNotExtern(
21330 } else {21335 } else {
21331 try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});21336 try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});
21332 },21337 },
21333 .Fn => switch (ty.fnCallingConvention()) {21338 .Fn => {
21334 .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}),21339 if (position != .other) {
21335 .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}),21340 try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{});
21336 .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}),21341 try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{});
21337 else => return,21342 return;
21343 }
21344 switch (ty.fnCallingConvention()) {
21345 .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}),
21346 .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}),
21347 .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}),
21348 else => return,
21349 }
21338 },21350 },
21339 .Enum => {21351 .Enum => {
21340 var buf: Type.Payload.Bits = undefined;21352 var buf: Type.Payload.Bits = undefined;
...@@ -21350,9 +21362,9 @@ fn explainWhyTypeIsNotExtern(...@@ -21350,9 +21362,9 @@ fn explainWhyTypeIsNotExtern(
21350 } else if (position == .param_ty) {21362 } else if (position == .param_ty) {
21351 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{});21363 return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{});
21352 }21364 }
21353 try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), position);21365 try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), .element);
21354 },21366 },
21355 .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), position),21367 .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), .element),
21356 .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}),21368 .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
21357 }21369 }
21358}21370}
...@@ -24849,13 +24861,13 @@ fn coerceVarArgParam(...@@ -24849,13 +24861,13 @@ fn coerceVarArgParam(
24849 };24861 };
2485024862
24851 const coerced_ty = sema.typeOf(coerced);24863 const coerced_ty = sema.typeOf(coerced);
24852 if (!try sema.validateExternType(block, inst_src, coerced_ty, .other)) {24864 if (!try sema.validateExternType(block, inst_src, coerced_ty, .param_ty)) {
24853 const msg = msg: {24865 const msg = msg: {
24854 const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)});24866 const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)});
24855 errdefer msg.destroy(sema.gpa);24867 errdefer msg.destroy(sema.gpa);
2485624868
24857 const src_decl = sema.mod.declPtr(block.src_decl);24869 const src_decl = sema.mod.declPtr(block.src_decl);
24858 try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .other);24870 try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .param_ty);
2485924871
24860 try sema.addDeclaredHereNote(msg, coerced_ty);24872 try sema.addDeclaredHereNote(msg, coerced_ty);
24861 break :msg msg;24873 break :msg msg;
...@@ -29144,14 +29156,14 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -29144,14 +29156,14 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
29144 };29156 };
29145 return sema.failWithOwnedErrorMsg(msg);29157 return sema.failWithOwnedErrorMsg(msg);
29146 }29158 }
29147 if (struct_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field.ty, .other)) {29159 if (struct_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field.ty, .struct_field)) {
29148 const msg = msg: {29160 const msg = msg: {
29149 const tree = try sema.getAstTree(&block_scope);29161 const tree = try sema.getAstTree(&block_scope);
29150 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i);29162 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i);
29151 const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});29163 const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
29152 errdefer msg.destroy(sema.gpa);29164 errdefer msg.destroy(sema.gpa);
2915329165
29154 try sema.explainWhyTypeIsNotExtern(msg, fields_src.toSrcLoc(decl), field.ty, .other);29166 try sema.explainWhyTypeIsNotExtern(msg, fields_src.toSrcLoc(decl), field.ty, .struct_field);
2915529167
29156 try sema.addDeclaredHereNote(msg, field.ty);29168 try sema.addDeclaredHereNote(msg, field.ty);
29157 break :msg msg;29169 break :msg msg;
test/cases/compile_errors/old_fn_ptr_in_extern_context.zig created+20
...@@ -0,0 +1,20 @@
1const S = extern struct {
2 a: fn () callconv(.C) void,
3};
4comptime {
5 _ = @sizeOf(S) == 1;
6}
7comptime {
8 _ = [*c][4]fn() callconv(.C) void;
9}
10
11// error
12// backend=stage2
13// target=native
14//
15// :2:5: error: extern structs cannot contain fields of type 'fn() callconv(.C) void'
16// :2:5: note: type has no guaranteed in-memory representation
17// :2:5: note: use '*const ' to make a function pointer type
18// :8:13: error: C pointers cannot point to non-C-ABI-compatible type '[4]fn() callconv(.C) void'
19// :8:13: note: type has no guaranteed in-memory representation
20// :8:13: note: use '*const ' to make a function pointer type