authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-22 18:21:03+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-23 15:40:12+03:00
log2436dd2c1b976f5902be6d20a93c164631ce3df5
tree2e8efabee27cfadf226dce06dae7e2b8ddbf0a6f
parent5b29275240a57448514fe5c5d9e8edae3b2362cc

Sema: validate duplicate fields in anon structs


7 files changed, 115 insertions(+), 36 deletions(-)

src/AstGen.zig+3-4
......@@ -1589,13 +1589,12 @@ fn structInitExpr(
15891589
15901590 switch (rl) {
15911591 .discard => {
1592 // TODO if a type expr is given the fields should be validated for that type
15931592 if (struct_init.ast.type_expr != 0) {
15941593 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
15951594 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1596 }
1597 for (struct_init.ast.fields) |field_init| {
1598 _ = try expr(gz, scope, .discard, field_init);
1595 _ = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1596 } else {
1597 _ = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
15991598 }
16001599 return Zir.Inst.Ref.void_value;
16011600 },
src/Module.zig+52
......@@ -5952,6 +5952,58 @@ pub fn argSrc(
59525952 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full.ast.params[arg_i]));
59535953}
59545954
5955pub fn initSrc(
5956 init_node_offset: i32,
5957 gpa: Allocator,
5958 decl: *Decl,
5959 init_index: usize,
5960) LazySrcLoc {
5961 @setCold(true);
5962 const tree = decl.getFileScope().getTree(gpa) catch |err| {
5963 // In this case we emit a warning + a less precise source location.
5964 log.warn("unable to load {s}: {s}", .{
5965 decl.getFileScope().sub_file_path, @errorName(err),
5966 });
5967 return LazySrcLoc.nodeOffset(0);
5968 };
5969 const node_tags = tree.nodes.items(.tag);
5970 const node = decl.relativeToNodeIndex(init_node_offset);
5971 var buf: [2]Ast.Node.Index = undefined;
5972 const full = switch (node_tags[node]) {
5973 .array_init_one, .array_init_one_comma => tree.arrayInitOne(buf[0..1], node).ast.elements,
5974 .array_init_dot_two, .array_init_dot_two_comma => tree.arrayInitDotTwo(&buf, node).ast.elements,
5975 .array_init_dot, .array_init_dot_comma => tree.arrayInitDot(node).ast.elements,
5976 .array_init, .array_init_comma => tree.arrayInit(node).ast.elements,
5977
5978 .struct_init_one, .struct_init_one_comma => tree.structInitOne(buf[0..1], node).ast.fields,
5979 .struct_init_dot_two, .struct_init_dot_two_comma => tree.structInitDotTwo(&buf, node).ast.fields,
5980 .struct_init_dot, .struct_init_dot_comma => tree.structInitDot(node).ast.fields,
5981 .struct_init, .struct_init_comma => tree.structInit(node).ast.fields,
5982 else => unreachable,
5983 };
5984 switch (node_tags[node]) {
5985 .array_init_one,
5986 .array_init_one_comma,
5987 .array_init_dot_two,
5988 .array_init_dot_two_comma,
5989 .array_init_dot,
5990 .array_init_dot_comma,
5991 .array_init,
5992 .array_init_comma,
5993 => return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full[init_index])),
5994 .struct_init_one,
5995 .struct_init_one_comma,
5996 .struct_init_dot_two,
5997 .struct_init_dot_two_comma,
5998 .struct_init_dot,
5999 .struct_init_dot_comma,
6000 .struct_init,
6001 .struct_init_comma,
6002 => return LazySrcLoc{ .node_offset_initializer = decl.nodeIndexToRelative(full[init_index]) },
6003 else => unreachable,
6004 }
6005}
6006
59556007/// Called from `performAllTheWork`, after all AstGen workers have finished,
59566008/// and before the main semantic analysis loop begins.
59576009pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
src/Sema.zig+39-11
......@@ -14721,22 +14721,41 @@ fn zirStructInitAnon(
1472114721 const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
1472214722 const types = try sema.arena.alloc(Type, extra.data.fields_len);
1472314723 const values = try sema.arena.alloc(Value, types.len);
14724 const names = try sema.arena.alloc([]const u8, types.len);
14724 var fields = std.StringArrayHashMapUnmanaged(u32){};
14725 defer fields.deinit(sema.gpa);
14726 try fields.ensureUnusedCapacity(sema.gpa, types.len);
1472514727
14726 const opt_runtime_src = rs: {
14727 var runtime_src: ?LazySrcLoc = null;
14728 const opt_runtime_index = rs: {
14729 var runtime_index: ?usize = null;
1472814730 var extra_index = extra.end;
1472914731 for (types) |*field_ty, i| {
14730 const init_src = src; // TODO better source location
1473114732 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
1473214733 extra_index = item.end;
1473314734
14734 names[i] = sema.code.nullTerminatedString(item.data.field_name);
14735 const name = sema.code.nullTerminatedString(item.data.field_name);
14736 const gop = fields.getOrPutAssumeCapacity(name);
14737 if (gop.found_existing) {
14738 const msg = msg: {
14739 const decl = sema.mod.declPtr(block.src_decl);
14740 const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i);
14741 const msg = try sema.errMsg(block, field_src, "duplicate field", .{});
14742 errdefer msg.destroy(sema.gpa);
14743
14744 const prev_source = Module.initSrc(src.node_offset.x, sema.gpa, decl, gop.value_ptr.*);
14745 try sema.errNote(block, prev_source, msg, "other field here", .{});
14746 break :msg msg;
14747 };
14748 return sema.failWithOwnedErrorMsg(block, msg);
14749 }
14750 gop.value_ptr.* = @intCast(u32, i);
14751
1473514752 const init = try sema.resolveInst(item.data.init);
1473614753 field_ty.* = sema.typeOf(init);
1473714754 if (types[i].zigTypeTag() == .Opaque) {
1473814755 const msg = msg: {
14739 const msg = try sema.errMsg(block, init_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
14756 const decl = sema.mod.declPtr(block.src_decl);
14757 const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i);
14758 const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
1474014759 errdefer msg.destroy(sema.gpa);
1474114760
1474214761 try sema.addDeclaredHereNote(msg, types[i]);
......@@ -14744,28 +14763,37 @@ fn zirStructInitAnon(
1474414763 };
1474514764 return sema.failWithOwnedErrorMsg(block, msg);
1474614765 }
14766 const init_src = src; // TODO better source location
1474714767 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
1474814768 values[i] = init_val;
1474914769 } else {
1475014770 values[i] = Value.initTag(.unreachable_value);
14751 runtime_src = init_src;
14771 runtime_index = i;
1475214772 }
1475314773 }
14754 break :rs runtime_src;
14774 break :rs runtime_index;
1475514775 };
1475614776
1475714777 const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{
14758 .names = names,
14778 .names = try sema.arena.dupe([]const u8, fields.keys()),
1475914779 .types = types,
1476014780 .values = values,
1476114781 });
1476214782
14763 const runtime_src = opt_runtime_src orelse {
14783 const runtime_index = opt_runtime_index orelse {
1476414784 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
1476514785 return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref);
1476614786 };
1476714787
14768 try sema.requireRuntimeBlock(block, src, runtime_src);
14788 sema.requireRuntimeBlock(block, src, .unneeded) catch |err| switch (err) {
14789 error.NeededSourceLocation => {
14790 const decl = sema.mod.declPtr(block.src_decl);
14791 const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index);
14792 try sema.requireRuntimeBlock(block, src, field_src);
14793 return error.AnalysisFail;
14794 },
14795 else => |e| return e,
14796 };
1476914797
1477014798 if (is_ref) {
1477114799 const target = sema.mod.getTarget();
test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig+1-1
......@@ -34,5 +34,5 @@ export fn d() void {
3434// :7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions
3535// :19:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs
3636// :18:22: note: opaque declared here
37// :24:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs
37// :24:23: error: opaque types have unknown size and therefore cannot be directly embedded in structs
3838// :23:22: note: opaque declared here
test/cases/compile_errors/duplicate_field_in_anonymous_struct_literal.zig created+18
......@@ -0,0 +1,18 @@
1export fn entry() void {
2 const anon = .{
3 .inner = .{
4 .a = .{
5 .something = "text",
6 },
7 .a = .{},
8 },
9 };
10 _ = anon;
11}
12
13// error
14// backend=stage2
15// target=native
16//
17// :7:16: error: duplicate field
18// :4:16: note: other field here
test/cases/compile_errors/invalid_store_to_comptime_field.zig+2-1
......@@ -58,4 +58,5 @@ pub export fn entry4() void {
5858// :14:19: error: value stored in comptime field does not match the default value of the field
5959// :19:38: error: value stored in comptime field does not match the default value of the field
6060// :31:19: error: value stored in comptime field does not match the default value of the field
61// :41:14: error: value stored in comptime field does not match the default value of the field
61// :25:29: note: default value set here
62// :41:16: error: value stored in comptime field does not match the default value of the field
test/cases/compile_errors/stage1/test/duplicate_field_in_anonymous_struct_literal.zig deleted-19
......@@ -1,19 +0,0 @@
1export fn entry() void {
2 const anon = .{
3 .inner = .{
4 .a = .{
5 .something = "text",
6 },
7 .a = .{},
8 },
9 };
10 _ = anon;
11}
12
13// error
14// backend=stage1
15// target=native
16// is_test=1
17//
18// tmp.zig:7:13: error: duplicate field
19// tmp.zig:4:13: note: other field here