commit 0a064eae9996ab8be0337bd6f286ce10c5bc8c0f (tree)
parent e165b8b223bfaaeb5953dec9a1f03b8e0ce4ddab
Author: Jacob G-W <jacoblevgw@gmail.com>
Date: Sun, 11 Sep 2022 19:08:02 -0400
stage2: detect duplicate enum values
Closes #12805
Diffstat:
3 files changed, 47 insertions(+), 23 deletions(-)
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -2691,11 +2691,11 @@ fn zirEnumDecl(
// This string needs to outlive the ZIR code.
const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
- const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
- if (gop.found_existing) {
+ const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);
+ if (gop_field.found_existing) {
const tree = try sema.getAstTree(block);
const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
- const other_tag_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop.index);
+ const other_tag_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_field.index);
const msg = msg: {
const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name});
errdefer msg.destroy(gpa);
@@ -2714,10 +2714,22 @@ fn zirEnumDecl(
const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime known")).val;
last_tag_val = tag_val;
const copied_tag_val = try tag_val.copy(decl_arena_allocator);
- enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
+ const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
.ty = enum_obj.tag_ty,
.mod = mod,
});
+ if (gop_val.found_existing) {
+ const tree = try sema.getAstTree(block);
+ const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
+ const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index);
+ const msg = msg: {
+ const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
} else if (any_values) {
const tag_val = if (last_tag_val) |val|
try sema.intAdd(block, src, val, Value.one, enum_obj.tag_ty)
@@ -2725,10 +2737,22 @@ fn zirEnumDecl(
Value.zero;
last_tag_val = tag_val;
const copied_tag_val = try tag_val.copy(decl_arena_allocator);
- enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
+ const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
.ty = enum_obj.tag_ty,
.mod = mod,
});
+ if (gop_val.found_existing) {
+ const tree = try sema.getAstTree(block);
+ const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
+ const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index);
+ const msg = msg: {
+ const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
} else {
tag_val_buf = .{
.base = .{ .tag = .int_u64 },
diff --git a/test/cases/compile_errors/enum_value_already_taken.zig b/test/cases/compile_errors/enum_value_already_taken.zig
@@ -0,0 +1,18 @@
+const MultipleChoice = enum(u32) {
+ A = 20,
+ B = 40,
+ C = 60,
+ D = 1000,
+ E = 60,
+};
+export fn entry() void {
+ var x = MultipleChoice.C;
+ _ = x;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :6:5: error: enum tag value 60 already taken
+// :4:5: note: other occurrence here
diff --git a/test/cases/compile_errors/stage1/obj/enum_value_already_taken.zig b/test/cases/compile_errors/stage1/obj/enum_value_already_taken.zig
@@ -1,18 +0,0 @@
-const MultipleChoice = enum(u32) {
- A = 20,
- B = 40,
- C = 60,
- D = 1000,
- E = 60,
-};
-export fn entry() void {
- var x = MultipleChoice.C;
- _ = x;
-}
-
-// error
-// backend=stage1
-// target=native
-//
-// tmp.zig:6:5: error: enum tag value 60 already taken
-// tmp.zig:4:5: note: other occurrence here