authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-20 12:30:11+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-21 12:21:30-07:00
log794beafb9c2c687d993a0933be258a2ccdf0be4f
treeca823524f3c46647f8cd79417faa5f471009f420
parent821e4063f9f32f71cce263265fdbacc632bd5af9

Sema: validate extern struct field types earlier

`validateExternType` does not require the type to be resolved so we can check it earlier. Only doing it in `resolveTypeFully` lead to worse or missing compile errors.

8 files changed, 129 insertions(+), 70 deletions(-)

src/Sema.zig+78-30
...@@ -14559,13 +14559,23 @@ fn zirStructInitAnon(...@@ -14559,13 +14559,23 @@ fn zirStructInitAnon(
14559 var runtime_src: ?LazySrcLoc = null;14559 var runtime_src: ?LazySrcLoc = null;
14560 var extra_index = extra.end;14560 var extra_index = extra.end;
14561 for (types) |*field_ty, i| {14561 for (types) |*field_ty, i| {
14562 const init_src = src; // TODO better source location
14562 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);14563 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
14563 extra_index = item.end;14564 extra_index = item.end;
1456414565
14565 names[i] = sema.code.nullTerminatedString(item.data.field_name);14566 names[i] = sema.code.nullTerminatedString(item.data.field_name);
14566 const init = try sema.resolveInst(item.data.init);14567 const init = try sema.resolveInst(item.data.init);
14567 field_ty.* = sema.typeOf(init);14568 field_ty.* = sema.typeOf(init);
14568 const init_src = src; // TODO better source location14569 if (types[i].zigTypeTag() == .Opaque) {
14570 const msg = msg: {
14571 const msg = try sema.errMsg(block, init_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
14572 errdefer msg.destroy(sema.gpa);
14573
14574 try sema.addDeclaredHereNote(msg, types[i]);
14575 break :msg msg;
14576 };
14577 return sema.failWithOwnedErrorMsg(block, msg);
14578 }
14569 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {14579 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
14570 values[i] = init_val;14580 values[i] = init_val;
14571 } else {14581 } else {
...@@ -14742,9 +14752,19 @@ fn zirArrayInitAnon(...@@ -14742,9 +14752,19 @@ fn zirArrayInitAnon(
14742 const opt_runtime_src = rs: {14752 const opt_runtime_src = rs: {
14743 var runtime_src: ?LazySrcLoc = null;14753 var runtime_src: ?LazySrcLoc = null;
14744 for (operands) |operand, i| {14754 for (operands) |operand, i| {
14755 const operand_src = src; // TODO better source location
14745 const elem = try sema.resolveInst(operand);14756 const elem = try sema.resolveInst(operand);
14746 types[i] = sema.typeOf(elem);14757 types[i] = sema.typeOf(elem);
14747 const operand_src = src; // TODO better source location14758 if (types[i].zigTypeTag() == .Opaque) {
14759 const msg = msg: {
14760 const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
14761 errdefer msg.destroy(sema.gpa);
14762
14763 try sema.addDeclaredHereNote(msg, types[i]);
14764 break :msg msg;
14765 };
14766 return sema.failWithOwnedErrorMsg(block, msg);
14767 }
14748 if (try sema.resolveMaybeUndefVal(block, operand_src, elem)) |val| {14768 if (try sema.resolveMaybeUndefVal(block, operand_src, elem)) |val| {
14749 values[i] = val;14769 values[i] = val;
14750 } else {14770 } else {
...@@ -18641,6 +18661,8 @@ const ExternPosition = enum {...@@ -18641,6 +18661,8 @@ const ExternPosition = enum {
18641 other,18661 other,
18642};18662};
1864318663
18664/// Returns true if `ty` is allowed in extern types.
18665/// Does *NOT* require `ty` to be resolved in any way.
18644fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) CompileError!bool {18666fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) CompileError!bool {
18645 switch (ty.zigTypeTag()) {18667 switch (ty.zigTypeTag()) {
18646 .Type,18668 .Type,
...@@ -25214,20 +25236,6 @@ fn resolveStructFully(...@@ -25214,20 +25236,6 @@ fn resolveStructFully(
25214 struct_obj.status = .fully_resolved_wip;25236 struct_obj.status = .fully_resolved_wip;
25215 for (struct_obj.fields.values()) |field| {25237 for (struct_obj.fields.values()) |field| {
25216 try sema.resolveTypeFully(block, src, field.ty);25238 try sema.resolveTypeFully(block, src, field.ty);
25217
25218 if (struct_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .other))) {
25219 const msg = msg: {
25220 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
25221 errdefer msg.destroy(sema.gpa);
25222
25223 const src_decl = sema.mod.declPtr(block.src_decl);
25224 try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), field.ty, .other);
25225
25226 try sema.addDeclaredHereNote(msg, field.ty);
25227 break :msg msg;
25228 };
25229 return sema.failWithOwnedErrorMsg(block, msg);
25230 }
25231 }25239 }
25232 struct_obj.status = .fully_resolved;25240 struct_obj.status = .fully_resolved;
25233 }25241 }
...@@ -25261,20 +25269,6 @@ fn resolveUnionFully(...@@ -25261,20 +25269,6 @@ fn resolveUnionFully(
25261 union_obj.status = .fully_resolved_wip;25269 union_obj.status = .fully_resolved_wip;
25262 for (union_obj.fields.values()) |field| {25270 for (union_obj.fields.values()) |field| {
25263 try sema.resolveTypeFully(block, src, field.ty);25271 try sema.resolveTypeFully(block, src, field.ty);
25264
25265 if (union_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .union_field))) {
25266 const msg = msg: {
25267 const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
25268 errdefer msg.destroy(sema.gpa);
25269
25270 const src_decl = sema.mod.declPtr(block.src_decl);
25271 try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), field.ty, .union_field);
25272
25273 try sema.addDeclaredHereNote(msg, field.ty);
25274 break :msg msg;
25275 };
25276 return sema.failWithOwnedErrorMsg(block, msg);
25277 }
25278 }25272 }
25279 union_obj.status = .fully_resolved;25273 union_obj.status = .fully_resolved;
25280 }25274 }
...@@ -25612,6 +25606,33 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -25612,6 +25606,33 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
25612 const field = &struct_obj.fields.values()[i];25606 const field = &struct_obj.fields.values()[i];
25613 field.ty = try field_ty.copy(decl_arena_allocator);25607 field.ty = try field_ty.copy(decl_arena_allocator);
2561425608
25609 if (struct_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .other))) {
25610 const msg = msg: {
25611 const tree = try sema.getAstTree(&block_scope);
25612 const fields_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i);
25613 const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
25614 errdefer msg.destroy(sema.gpa);
25615
25616 try sema.explainWhyTypeIsNotExtern(&block_scope, fields_src, msg, fields_src.toSrcLoc(decl), field.ty, .other);
25617
25618 try sema.addDeclaredHereNote(msg, field.ty);
25619 break :msg msg;
25620 };
25621 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25622 }
25623 if (field_ty.zigTypeTag() == .Opaque) {
25624 const msg = msg: {
25625 const tree = try sema.getAstTree(&block_scope);
25626 const field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i);
25627 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
25628 errdefer msg.destroy(sema.gpa);
25629
25630 try sema.addDeclaredHereNote(msg, field_ty);
25631 break :msg msg;
25632 };
25633 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25634 }
25635
25615 if (zir_field.align_body_len > 0) {25636 if (zir_field.align_body_len > 0) {
25616 const body = zir.extra[extra_index..][0..zir_field.align_body_len];25637 const body = zir.extra[extra_index..][0..zir_field.align_body_len];
25617 extra_index += body.len;25638 extra_index += body.len;
...@@ -25909,6 +25930,33 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -25909,6 +25930,33 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
25909 }25930 }
25910 }25931 }
2591125932
25933 if (union_obj.layout == .Extern and !(try sema.validateExternType(field_ty, .union_field))) {
25934 const msg = msg: {
25935 const tree = try sema.getAstTree(&block_scope);
25936 const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);
25937 const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
25938 errdefer msg.destroy(sema.gpa);
25939
25940 try sema.explainWhyTypeIsNotExtern(&block_scope, field_src, msg, field_src.toSrcLoc(decl), field_ty, .union_field);
25941
25942 try sema.addDeclaredHereNote(msg, field_ty);
25943 break :msg msg;
25944 };
25945 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25946 }
25947 if (field_ty.zigTypeTag() == .Opaque) {
25948 const msg = msg: {
25949 const tree = try sema.getAstTree(&block_scope);
25950 const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);
25951 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
25952 errdefer msg.destroy(sema.gpa);
25953
25954 try sema.addDeclaredHereNote(msg, field_ty);
25955 break :msg msg;
25956 };
25957 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25958 }
25959
25912 gop.value_ptr.* = .{25960 gop.value_ptr.* = .{
25913 .ty = try field_ty.copy(decl_arena_allocator),25961 .ty = try field_ty.copy(decl_arena_allocator),
25914 .abi_align = 0,25962 .abi_align = 0,
test/behavior/align.zig+2-2
...@@ -299,7 +299,7 @@ test "implicitly decreasing fn alignment" {...@@ -299,7 +299,7 @@ test "implicitly decreasing fn alignment" {
299 try testImplicitlyDecreaseFnAlign(alignedBig, 5678);299 try testImplicitlyDecreaseFnAlign(alignedBig, 5678);
300}300}
301301
302fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void {302fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(1) i32, answer: i32) !void {
303 try expect(ptr() == answer);303 try expect(ptr() == answer);
304}304}
305305
...@@ -325,7 +325,7 @@ test "@alignCast functions" {...@@ -325,7 +325,7 @@ test "@alignCast functions" {
325fn fnExpectsOnly1(ptr: *const fn () align(1) i32) i32 {325fn fnExpectsOnly1(ptr: *const fn () align(1) i32) i32 {
326 return fnExpects4(@alignCast(4, ptr));326 return fnExpects4(@alignCast(4, ptr));
327}327}
328fn fnExpects4(ptr: *align(4) const fn () i32) i32 {328fn fnExpects4(ptr: *const fn () align(4) i32) i32 {
329 return ptr();329 return ptr();
330}330}
331fn simple4() align(4) i32 {331fn simple4() align(4) i32 {
test/behavior/bugs/1310.zig+3-1
...@@ -4,7 +4,7 @@ const builtin = @import("builtin");...@@ -4,7 +4,7 @@ const builtin = @import("builtin");
44
5pub const VM = ?[*]const struct_InvocationTable_;5pub const VM = ?[*]const struct_InvocationTable_;
6pub const struct_InvocationTable_ = extern struct {6pub const struct_InvocationTable_ = extern struct {
7 GetVM: ?fn (?[*]VM) callconv(.C) c_int,7 GetVM: ?*const fn (?[*]VM) callconv(.C) c_int,
8};8};
99
10pub const struct_VM_ = extern struct {10pub const struct_VM_ = extern struct {
...@@ -23,5 +23,7 @@ fn agent_callback(_vm: [*]VM, options: [*]u8) callconv(.C) i32 {...@@ -23,5 +23,7 @@ fn agent_callback(_vm: [*]VM, options: [*]u8) callconv(.C) i32 {
23}23}
2424
25test "fixed" {25test "fixed" {
26 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
27 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
26 try expect(agent_callback(undefined, undefined) == 11);28 try expect(agent_callback(undefined, undefined) == 11);
27}29}
test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig created+38
...@@ -0,0 +1,38 @@
1const O = opaque {};
2const Foo = struct {
3 o: O,
4};
5const Bar = union {
6 One: i32,
7 Two: O,
8};
9export fn a() void {
10 var foo: Foo = undefined;
11 _ = foo;
12}
13export fn b() void {
14 var bar: Bar = undefined;
15 _ = bar;
16}
17export fn c() void {
18 const baz = &@as(opaque {}, undefined);
19 const qux = .{baz.*};
20 _ = qux;
21}
22export fn d() void {
23 const baz = &@as(opaque {}, undefined);
24 const qux = .{ .a = baz.* };
25 _ = qux;
26}
27
28// error
29// backend=stage2
30// target=native
31//
32// :3:5: error: opaque types have unknown size and therefore cannot be directly embedded in structs
33// :1:11: note: opaque declared here
34// :7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions
35// :19:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs
36// :18:22: note: opaque declared here
37// :24:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs
38// :23:22: note: opaque declared here
test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig+3-3
...@@ -39,7 +39,7 @@ export fn entry() void {...@@ -39,7 +39,7 @@ export fn entry() void {
39// backend=stage239// backend=stage2
40// target=native40// target=native
41//41//
42// :33:8: error: extern structs cannot contain fields of type 'tmp.E'42// :31:5: error: extern structs cannot contain fields of type 'tmp.E'
43// :33:8: note: enum tag type 'u9' is not extern compatible43// :31:5: note: enum tag type 'u9' is not extern compatible
44// :33:8: note: only integers with power of two bits are extern compatible44// :31:5: note: only integers with power of two bits are extern compatible
45// :1:15: note: enum declared here45// :1:15: note: enum declared here
test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig+3-3
...@@ -11,7 +11,7 @@ export fn entry() void {...@@ -11,7 +11,7 @@ export fn entry() void {
11// backend=stage211// backend=stage2
12// target=native12// target=native
13//13//
14// :5:8: error: extern structs cannot contain fields of type 'tmp.E'14// :3:5: error: extern structs cannot contain fields of type 'tmp.E'
15// :5:8: note: enum tag type 'u31' is not extern compatible15// :3:5: note: enum tag type 'u31' is not extern compatible
16// :5:8: note: only integers with power of two bits are extern compatible16// :3:5: note: only integers with power of two bits are extern compatible
17// :1:15: note: enum declared here17// :1:15: note: enum declared here
test/cases/compile_errors/invalid_optional_type_in_extern_struct.zig+2-2
...@@ -7,5 +7,5 @@ export fn testf(fluff: *stroo) void { _ = fluff; }...@@ -7,5 +7,5 @@ export fn testf(fluff: *stroo) void { _ = fluff; }
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :4:8: error: extern structs cannot contain fields of type '?[*c]u8'10// :2:5: error: extern structs cannot contain fields of type '?[*c]u8'
11// :4:8: note: only pointer like optionals are extern compatible11// :2:5: note: only pointer like optionals are extern compatible
test/cases/compile_errors/stage1/obj/directly_embedding_opaque_type_in_struct_and_union.zig deleted-29
...@@ -1,29 +0,0 @@
1const O = opaque {};
2const Foo = struct {
3 o: O,
4};
5const Bar = union {
6 One: i32,
7 Two: O,
8};
9export fn a() void {
10 var foo: Foo = undefined;
11 _ = foo;
12}
13export fn b() void {
14 var bar: Bar = undefined;
15 _ = bar;
16}
17export fn c() void {
18 var baz: *opaque {} = undefined;
19 const qux = .{baz.*};
20 _ = qux;
21}
22
23// error
24// backend=stage1
25// target=native
26//
27// tmp.zig:3:5: error: opaque types have unknown size and therefore cannot be directly embedded in structs
28// tmp.zig:7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions
29// tmp.zig:19:22: error: opaque types have unknown size and therefore cannot be directly embedded in structs