authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2022-09-11 19:08:02-04:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-09-28 12:48:54+03:00
log0a064eae9996ab8be0337bd6f286ce10c5bc8c0f
tree1da29b66f7c88899299af734575a02de10fa4ec2
parente165b8b223bfaaeb5953dec9a1f03b8e0ce4ddab

stage2: detect duplicate enum values

Closes #12805

3 files changed, 47 insertions(+), 23 deletions(-)

src/Sema.zig+29-5
......@@ -2691,11 +2691,11 @@ fn zirEnumDecl(
26912691 // This string needs to outlive the ZIR code.
26922692 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
26932693
2694 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
2695 if (gop.found_existing) {
2694 const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);
2695 if (gop_field.found_existing) {
26962696 const tree = try sema.getAstTree(block);
26972697 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
2698 const other_tag_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop.index);
2698 const other_tag_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_field.index);
26992699 const msg = msg: {
27002700 const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name});
27012701 errdefer msg.destroy(gpa);
......@@ -2714,10 +2714,22 @@ fn zirEnumDecl(
27142714 const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime known")).val;
27152715 last_tag_val = tag_val;
27162716 const copied_tag_val = try tag_val.copy(decl_arena_allocator);
2717 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
2717 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
27182718 .ty = enum_obj.tag_ty,
27192719 .mod = mod,
27202720 });
2721 if (gop_val.found_existing) {
2722 const tree = try sema.getAstTree(block);
2723 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
2724 const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index);
2725 const msg = msg: {
2726 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
2727 errdefer msg.destroy(gpa);
2728 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
2729 break :msg msg;
2730 };
2731 return sema.failWithOwnedErrorMsg(msg);
2732 }
27212733 } else if (any_values) {
27222734 const tag_val = if (last_tag_val) |val|
27232735 try sema.intAdd(block, src, val, Value.one, enum_obj.tag_ty)
......@@ -2725,10 +2737,22 @@ fn zirEnumDecl(
27252737 Value.zero;
27262738 last_tag_val = tag_val;
27272739 const copied_tag_val = try tag_val.copy(decl_arena_allocator);
2728 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
2740 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
27292741 .ty = enum_obj.tag_ty,
27302742 .mod = mod,
27312743 });
2744 if (gop_val.found_existing) {
2745 const tree = try sema.getAstTree(block);
2746 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
2747 const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index);
2748 const msg = msg: {
2749 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
2750 errdefer msg.destroy(gpa);
2751 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
2752 break :msg msg;
2753 };
2754 return sema.failWithOwnedErrorMsg(msg);
2755 }
27322756 } else {
27332757 tag_val_buf = .{
27342758 .base = .{ .tag = .int_u64 },
test/cases/compile_errors/enum_value_already_taken.zig created+18
......@@ -0,0 +1,18 @@
1const MultipleChoice = enum(u32) {
2 A = 20,
3 B = 40,
4 C = 60,
5 D = 1000,
6 E = 60,
7};
8export fn entry() void {
9 var x = MultipleChoice.C;
10 _ = x;
11}
12
13// error
14// backend=stage2
15// target=native
16//
17// :6:5: error: enum tag value 60 already taken
18// :4:5: note: other occurrence here
test/cases/compile_errors/stage1/obj/enum_value_already_taken.zig deleted-18
......@@ -1,18 +0,0 @@
1const MultipleChoice = enum(u32) {
2 A = 20,
3 B = 40,
4 C = 60,
5 D = 1000,
6 E = 60,
7};
8export fn entry() void {
9 var x = MultipleChoice.C;
10 _ = x;
11}
12
13// error
14// backend=stage1
15// target=native
16//
17// tmp.zig:6:5: error: enum tag value 60 already taken
18// tmp.zig:4:5: note: other occurrence here