| author | |
| committer | |
| log | 941090d94f6b6c7c5207f06917743e79ff06426f |
| tree | 89a9cbd53f32e26b39779f997aecb1ce090ee75d |
| parent | acf9de376d176d35dcfd245d14939766aeba4638 |
| signature |
Partially addresses #17916.10 files changed, 146 insertions(+), 67 deletions(-)
lib/std/os/linux/sparc64.zig+1-1| ... | ... | @@ -445,7 +445,7 @@ pub const ucontext_t = extern struct { |
| 445 | 445 | sigmask: u64, |
| 446 | 446 | mcontext: mcontext_t, |
| 447 | 447 | stack: stack_t, |
| 448 | sigmask: sigset_t, | |
| 448 | sigset: sigset_t, | |
| 449 | 449 | }; |
| 450 | 450 | |
| 451 | 451 | pub const rlimit_resource = enum(c_int) { |
src/AstGen.zig+100-1| ... | ... | @@ -1722,6 +1722,57 @@ fn structInitExpr( |
| 1722 | 1722 | } |
| 1723 | 1723 | } |
| 1724 | 1724 | |
| 1725 | { | |
| 1726 | var sfba = std.heap.stackFallback(256, astgen.arena); | |
| 1727 | const sfba_allocator = sfba.get(); | |
| 1728 | ||
| 1729 | var duplicate_names = std.AutoArrayHashMap(u32, ArrayListUnmanaged(Ast.TokenIndex)).init(sfba_allocator); | |
| 1730 | defer duplicate_names.deinit(); | |
| 1731 | try duplicate_names.ensureTotalCapacity(@intCast(struct_init.ast.fields.len)); | |
| 1732 | ||
| 1733 | // When there aren't errors, use this to avoid a second iteration. | |
| 1734 | var any_duplicate = false; | |
| 1735 | ||
| 1736 | for (struct_init.ast.fields) |field| { | |
| 1737 | const name_token = tree.firstToken(field) - 2; | |
| 1738 | const name_index = try astgen.identAsString(name_token); | |
| 1739 | ||
| 1740 | const gop = try duplicate_names.getOrPut(name_index); | |
| 1741 | ||
| 1742 | if (gop.found_existing) { | |
| 1743 | try gop.value_ptr.append(sfba_allocator, name_token); | |
| 1744 | any_duplicate = true; | |
| 1745 | } else { | |
| 1746 | gop.value_ptr.* = .{}; | |
| 1747 | try gop.value_ptr.append(sfba_allocator, name_token); | |
| 1748 | } | |
| 1749 | } | |
| 1750 | ||
| 1751 | if (any_duplicate) { | |
| 1752 | var it = duplicate_names.iterator(); | |
| 1753 | ||
| 1754 | while (it.next()) |entry| { | |
| 1755 | const record = entry.value_ptr.*; | |
| 1756 | if (record.items.len > 1) { | |
| 1757 | var error_notes = std.ArrayList(u32).init(astgen.arena); | |
| 1758 | ||
| 1759 | for (record.items[1..]) |duplicate| { | |
| 1760 | try error_notes.append(try astgen.errNoteTok(duplicate, "other field here", .{})); | |
| 1761 | } | |
| 1762 | ||
| 1763 | try astgen.appendErrorTokNotes( | |
| 1764 | record.items[0], | |
| 1765 | "duplicate field", | |
| 1766 | .{}, | |
| 1767 | error_notes.items, | |
| 1768 | ); | |
| 1769 | } | |
| 1770 | } | |
| 1771 | ||
| 1772 | return error.AnalysisFail; | |
| 1773 | } | |
| 1774 | } | |
| 1775 | ||
| 1725 | 1776 | if (struct_init.ast.type_expr != 0) { |
| 1726 | 1777 | // Typed inits do not use RLS for language simplicity. |
| 1727 | 1778 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| ... | ... | @@ -4874,6 +4925,15 @@ fn structDeclInner( |
| 4874 | 4925 | } |
| 4875 | 4926 | }; |
| 4876 | 4927 | |
| 4928 | var sfba = std.heap.stackFallback(256, astgen.arena); | |
| 4929 | const sfba_allocator = sfba.get(); | |
| 4930 | ||
| 4931 | var duplicate_names = std.AutoArrayHashMap(u32, std.ArrayListUnmanaged(Ast.TokenIndex)).init(sfba_allocator); | |
| 4932 | try duplicate_names.ensureTotalCapacity(field_count); | |
| 4933 | ||
| 4934 | // When there aren't errors, use this to avoid a second iteration. | |
| 4935 | var any_duplicate = false; | |
| 4936 | ||
| 4877 | 4937 | var known_non_opv = false; |
| 4878 | 4938 | var known_comptime_only = false; |
| 4879 | 4939 | var any_comptime_fields = false; |
| ... | ... | @@ -4886,11 +4946,22 @@ fn structDeclInner( |
| 4886 | 4946 | }; |
| 4887 | 4947 | |
| 4888 | 4948 | if (!is_tuple) { |
| 4949 | const field_name = try astgen.identAsString(member.ast.main_token); | |
| 4950 | ||
| 4889 | 4951 | member.convertToNonTupleLike(astgen.tree.nodes); |
| 4890 | 4952 | assert(!member.ast.tuple_like); |
| 4891 | 4953 | |
| 4892 | const field_name = try astgen.identAsString(member.ast.main_token); | |
| 4893 | 4954 | wip_members.appendToField(field_name); |
| 4955 | ||
| 4956 | const gop = try duplicate_names.getOrPut(field_name); | |
| 4957 | ||
| 4958 | if (gop.found_existing) { | |
| 4959 | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); | |
| 4960 | any_duplicate = true; | |
| 4961 | } else { | |
| 4962 | gop.value_ptr.* = .{}; | |
| 4963 | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); | |
| 4964 | } | |
| 4894 | 4965 | } else if (!member.ast.tuple_like) { |
| 4895 | 4966 | return astgen.failTok(member.ast.main_token, "tuple field has a name", .{}); |
| 4896 | 4967 | } |
| ... | ... | @@ -4975,6 +5046,34 @@ fn structDeclInner( |
| 4975 | 5046 | } |
| 4976 | 5047 | } |
| 4977 | 5048 | |
| 5049 | if (any_duplicate) { | |
| 5050 | var it = duplicate_names.iterator(); | |
| 5051 | ||
| 5052 | while (it.next()) |entry| { | |
| 5053 | const record = entry.value_ptr.*; | |
| 5054 | if (record.items.len > 1) { | |
| 5055 | var error_notes = std.ArrayList(u32).init(astgen.arena); | |
| 5056 | ||
| 5057 | for (record.items[1..]) |duplicate| { | |
| 5058 | try error_notes.append(try astgen.errNoteTok(duplicate, "other field here", .{})); | |
| 5059 | } | |
| 5060 | ||
| 5061 | try error_notes.append(try astgen.errNoteNode(node, "struct declared here", .{})); | |
| 5062 | ||
| 5063 | try astgen.appendErrorTokNotes( | |
| 5064 | record.items[0], | |
| 5065 | "duplicate struct field: '{s}'", | |
| 5066 | .{try astgen.identifierTokenString(record.items[0])}, | |
| 5067 | error_notes.items, | |
| 5068 | ); | |
| 5069 | } | |
| 5070 | } | |
| 5071 | ||
| 5072 | return error.AnalysisFail; | |
| 5073 | } | |
| 5074 | ||
| 5075 | duplicate_names.deinit(); | |
| 5076 | ||
| 4978 | 5077 | try gz.setStruct(decl_inst, .{ |
| 4979 | 5078 | .src_node = node, |
| 4980 | 5079 | .layout = layout, |
src/Sema.zig+11-48| ... | ... | @@ -4690,17 +4690,7 @@ fn validateStructInit( |
| 4690 | 4690 | try sema.tupleFieldIndex(block, struct_ty, field_name, field_src) |
| 4691 | 4691 | else |
| 4692 | 4692 | try sema.structFieldIndex(block, struct_ty, field_name, field_src); |
| 4693 | if (found_fields[field_index.*].unwrap()) |other_field_ptr| { | |
| 4694 | const other_field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(other_field_ptr)].pl_node; | |
| 4695 | const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_ptr_data.src_node }; | |
| 4696 | const msg = msg: { | |
| 4697 | const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); | |
| 4698 | errdefer msg.destroy(gpa); | |
| 4699 | try sema.errNote(block, other_field_src, msg, "other field here", .{}); | |
| 4700 | break :msg msg; | |
| 4701 | }; | |
| 4702 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 4703 | } | |
| 4693 | assert(found_fields[field_index.*] == .none); | |
| 4704 | 4694 | found_fields[field_index.*] = field_ptr.toOptional(); |
| 4705 | 4695 | } |
| 4706 | 4696 | |
| ... | ... | @@ -19222,18 +19212,7 @@ fn zirStructInit( |
| 19222 | 19212 | try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src) |
| 19223 | 19213 | else |
| 19224 | 19214 | try sema.structFieldIndex(block, resolved_ty, field_name, field_src); |
| 19225 | if (field_inits[field_index] != .none) { | |
| 19226 | const other_field_type = found_fields[field_index]; | |
| 19227 | const other_field_type_data = zir_datas[@intFromEnum(other_field_type)].pl_node; | |
| 19228 | const other_field_src: LazySrcLoc = .{ .node_offset_initializer = other_field_type_data.src_node }; | |
| 19229 | const msg = msg: { | |
| 19230 | const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); | |
| 19231 | errdefer msg.destroy(gpa); | |
| 19232 | try sema.errNote(block, other_field_src, msg, "other field here", .{}); | |
| 19233 | break :msg msg; | |
| 19234 | }; | |
| 19235 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 19236 | } | |
| 19215 | assert(field_inits[field_index] == .none); | |
| 19237 | 19216 | found_fields[field_index] = item.data.field_type; |
| 19238 | 19217 | const uncoerced_init = try sema.resolveInst(item.data.init); |
| 19239 | 19218 | const field_ty = resolved_ty.structFieldType(field_index, mod); |
| ... | ... | @@ -19533,16 +19512,13 @@ fn structInitAnon( |
| 19533 | 19512 | |
| 19534 | 19513 | const types = try sema.arena.alloc(InternPool.Index, extra_data.fields_len); |
| 19535 | 19514 | const values = try sema.arena.alloc(InternPool.Index, types.len); |
| 19536 | ||
| 19537 | var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena); | |
| 19538 | try fields.ensureUnusedCapacity(types.len); | |
| 19515 | const names = try sema.arena.alloc(InternPool.NullTerminatedString, types.len); | |
| 19539 | 19516 | |
| 19540 | 19517 | // Find which field forces the expression to be runtime, if any. |
| 19541 | 19518 | const opt_runtime_index = rs: { |
| 19542 | 19519 | var runtime_index: ?usize = null; |
| 19543 | 19520 | var extra_index = extra_end; |
| 19544 | for (types, 0..) |*field_ty, i_usize| { | |
| 19545 | const i: u32 = @intCast(i_usize); | |
| 19521 | for (types, values, names, 0..) |*field_ty, *field_val, *field_name, i_usize| { | |
| 19546 | 19522 | const item = switch (kind) { |
| 19547 | 19523 | .anon_init => sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index), |
| 19548 | 19524 | .typed_init => sema.code.extraData(Zir.Inst.StructInit.Item, extra_index), |
| ... | ... | @@ -19558,29 +19534,16 @@ fn structInitAnon( |
| 19558 | 19534 | break :name sema.code.nullTerminatedString(field_type_extra.data.name_start); |
| 19559 | 19535 | }, |
| 19560 | 19536 | }; |
| 19561 | const name_ip = try mod.intern_pool.getOrPutString(gpa, name); | |
| 19562 | const gop = fields.getOrPutAssumeCapacity(name_ip); | |
| 19563 | if (gop.found_existing) { | |
| 19564 | const msg = msg: { | |
| 19565 | const decl = mod.declPtr(block.src_decl); | |
| 19566 | const field_src = mod.initSrc(src.node_offset.x, decl, i); | |
| 19567 | const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); | |
| 19568 | errdefer msg.destroy(gpa); | |
| 19569 | 19537 | |
| 19570 | const prev_source = mod.initSrc(src.node_offset.x, decl, gop.value_ptr.*); | |
| 19571 | try sema.errNote(block, prev_source, msg, "other field here", .{}); | |
| 19572 | break :msg msg; | |
| 19573 | }; | |
| 19574 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 19575 | } | |
| 19576 | gop.value_ptr.* = i; | |
| 19538 | const name_ip = try mod.intern_pool.getOrPutString(gpa, name); | |
| 19539 | field_name.* = name_ip; | |
| 19577 | 19540 | |
| 19578 | 19541 | const init = try sema.resolveInst(item.data.init); |
| 19579 | 19542 | field_ty.* = sema.typeOf(init).toIntern(); |
| 19580 | 19543 | if (field_ty.toType().zigTypeTag(mod) == .Opaque) { |
| 19581 | 19544 | const msg = msg: { |
| 19582 | 19545 | const decl = mod.declPtr(block.src_decl); |
| 19583 | const field_src = mod.initSrc(src.node_offset.x, decl, i); | |
| 19546 | const field_src = mod.initSrc(src.node_offset.x, decl, @intCast(i_usize)); | |
| 19584 | 19547 | const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 19585 | 19548 | errdefer msg.destroy(sema.gpa); |
| 19586 | 19549 | |
| ... | ... | @@ -19590,17 +19553,17 @@ fn structInitAnon( |
| 19590 | 19553 | return sema.failWithOwnedErrorMsg(block, msg); |
| 19591 | 19554 | } |
| 19592 | 19555 | if (try sema.resolveValue(init)) |init_val| { |
| 19593 | values[i] = try init_val.intern(field_ty.toType(), mod); | |
| 19556 | field_val.* = try init_val.intern(field_ty.toType(), mod); | |
| 19594 | 19557 | } else { |
| 19595 | values[i] = .none; | |
| 19596 | runtime_index = i; | |
| 19558 | field_val.* = .none; | |
| 19559 | runtime_index = @intCast(i_usize); | |
| 19597 | 19560 | } |
| 19598 | 19561 | } |
| 19599 | 19562 | break :rs runtime_index; |
| 19600 | 19563 | }; |
| 19601 | 19564 | |
| 19602 | 19565 | const tuple_ty = try ip.getAnonStructType(gpa, .{ |
| 19603 | .names = fields.keys(), | |
| 19566 | .names = names, | |
| 19604 | 19567 | .types = types, |
| 19605 | 19568 | .values = values, |
| 19606 | 19569 | }); |
test/cases/compile_errors/duplicate_field_in_anonymous_struct_literal.zig+2-2| ... | ... | @@ -14,5 +14,5 @@ export fn entry() void { |
| 14 | 14 | // backend=stage2 |
| 15 | 15 | // target=native |
| 16 | 16 | // |
| 17 | // :7:16: error: duplicate field | |
| 18 | // :4:16: note: other field here | |
| 17 | // :4:14: error: duplicate field | |
| 18 | // :7:14: note: other field here |
test/cases/compile_errors/duplicate_field_in_discarded_anon_init.zig+2-2| ... | ... | @@ -6,5 +6,5 @@ pub export fn entry() void { |
| 6 | 6 | // backend=stage2 |
| 7 | 7 | // target=native |
| 8 | 8 | // |
| 9 | // :2:21: error: duplicate field | |
| 10 | // :2:13: note: other field here | |
| 9 | // :2:13: error: duplicate field | |
| 10 | // :2:21: note: other field here |
test/cases/compile_errors/duplicate_field_in_struct_value_expression.zig+2-2| ... | ... | @@ -17,5 +17,5 @@ export fn f() void { |
| 17 | 17 | // backend=stage2 |
| 18 | 18 | // target=native |
| 19 | 19 | // |
| 20 | // :11:10: error: duplicate field | |
| 21 | // :8:10: note: other field here | |
| 20 | // :8:10: error: duplicate field | |
| 21 | // :11:10: note: other field here |
test/cases/compile_errors/duplicate_struct_field.zig+22-5| ... | ... | @@ -2,15 +2,32 @@ const Foo = struct { |
| 2 | 2 | Bar: i32, |
| 3 | 3 | Bar: usize, |
| 4 | 4 | }; |
| 5 | export fn entry() void { | |
| 6 | const a: Foo = undefined; | |
| 7 | _ = a; | |
| 5 | ||
| 6 | const S = struct { | |
| 7 | a: u32, | |
| 8 | b: u32, | |
| 9 | a: u32, | |
| 10 | a: u64, | |
| 11 | }; | |
| 12 | ||
| 13 | export fn a() void { | |
| 14 | const f: Foo = undefined; | |
| 15 | _ = f; | |
| 16 | } | |
| 17 | ||
| 18 | export fn b() void { | |
| 19 | const s: S = undefined; | |
| 20 | _ = s; | |
| 8 | 21 | } |
| 9 | 22 | |
| 10 | 23 | // error |
| 11 | 24 | // backend=stage2 |
| 12 | 25 | // target=native |
| 13 | 26 | // |
| 14 | // :3:5: error: duplicate struct field: 'Bar' | |
| 15 | // :2:5: note: other field here | |
| 27 | // :2:5: error: duplicate struct field: 'Bar' | |
| 28 | // :3:5: note: other field here | |
| 16 | 29 | // :1:13: note: struct declared here |
| 30 | // :7:5: error: duplicate struct field: 'a' | |
| 31 | // :9:5: note: other field here | |
| 32 | // :10:5: note: other field here | |
| 33 | // :6:11: note: struct declared here |
test/cases/compile_errors/error_in_struct_initializer_doesnt_crash_the_compiler.zig+2-2| ... | ... | @@ -11,6 +11,6 @@ pub export fn entry() void { |
| 11 | 11 | // backend=stage2 |
| 12 | 12 | // target=native |
| 13 | 13 | // |
| 14 | // :4:9: error: duplicate struct field: 'e' | |
| 15 | // :3:9: note: other field here | |
| 14 | // :3:9: error: duplicate struct field: 'e' | |
| 15 | // :4:9: note: other field here | |
| 16 | 16 | // :2:22: note: struct declared here |
test/cases/compile_errors/struct_duplicate_field_name.zig+2-2| ... | ... | @@ -11,6 +11,6 @@ export fn entry() void { |
| 11 | 11 | // error |
| 12 | 12 | // target=native |
| 13 | 13 | // |
| 14 | // :3:5: error: duplicate struct field: 'foo' | |
| 15 | // :2:5: note: other field here | |
| 14 | // :2:5: error: duplicate struct field: 'foo' | |
| 15 | // :3:5: note: other field here | |
| 16 | 16 | // :1:11: note: struct declared here |
test/cbe.zig+2-2| ... | ... | @@ -507,8 +507,8 @@ pub fn addCases(ctx: *Cases) !void { |
| 507 | 507 | \\ return p.y - p.x - p.x; |
| 508 | 508 | \\} |
| 509 | 509 | , &.{ |
| 510 | ":6:10: error: duplicate field", | |
| 511 | ":4:10: note: other field here", | |
| 510 | ":4:10: error: duplicate field", | |
| 511 | ":6:10: note: other field here", | |
| 512 | 512 | }); |
| 513 | 513 | case.addError( |
| 514 | 514 | \\const Point = struct { x: i32, y: i32 }; |