authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-17 16:10:46+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-17 23:03:04+03:00
log233049503a41ac4c6895f7126cda63349606b8f8
tree677516eaec96eea8056676d77aa97cca94c06b1f
parentc3d5428cba4d02afbe1ec34bdc7bcb68f56d1b45

Sema: allow empty enums and unions


13 files changed, 153 insertions(+), 175 deletions(-)

src/AstGen.zig-9
...@@ -4557,9 +4557,6 @@ fn unionDeclInner(...@@ -4557,9 +4557,6 @@ fn unionDeclInner(
4557 wip_members.appendToField(@enumToInt(tag_value));4557 wip_members.appendToField(@enumToInt(tag_value));
4558 }4558 }
4559 }4559 }
4560 if (field_count == 0) {
4561 return astgen.failNode(node, "union declarations must have at least one tag", .{});
4562 }
45634560
4564 if (!block_scope.isEmpty()) {4561 if (!block_scope.isEmpty()) {
4565 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);4562 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
...@@ -4715,12 +4712,6 @@ fn containerDecl(...@@ -4715,12 +4712,6 @@ fn containerDecl(
4715 .nonexhaustive_node = nonexhaustive_node,4712 .nonexhaustive_node = nonexhaustive_node,
4716 };4713 };
4717 };4714 };
4718 if (counts.total_fields == 0 and counts.nonexhaustive_node == 0) {
4719 // One can construct an enum with no tags, and it functions the same as `noreturn`. But
4720 // this is only useful for generic code; when explicitly using `enum {}` syntax, there
4721 // must be at least one tag.
4722 try astgen.appendErrorNode(node, "enum declarations must have at least one tag", .{});
4723 }
4724 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {4715 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {
4725 try astgen.appendErrorNodeNotes(4716 try astgen.appendErrorNodeNotes(
4726 node,4717 node,
src/Sema.zig+84-84
...@@ -8979,6 +8979,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8979,6 +8979,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8979 var seen_union_fields: []?Module.SwitchProngSrc = &.{};8979 var seen_union_fields: []?Module.SwitchProngSrc = &.{};
8980 defer gpa.free(seen_union_fields);8980 defer gpa.free(seen_union_fields);
89818981
8982 var empty_enum = false;
8983
8982 const operand_ty = sema.typeOf(operand);8984 const operand_ty = sema.typeOf(operand);
89838985
8984 var else_error_ty: ?Type = null;8986 var else_error_ty: ?Type = null;
...@@ -9012,6 +9014,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9012,6 +9014,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9012 .Union => unreachable, // handled in zirSwitchCond9014 .Union => unreachable, // handled in zirSwitchCond
9013 .Enum => {9015 .Enum => {
9014 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());9016 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());
9017 empty_enum = seen_fields.len == 0 and !operand_ty.isNonexhaustiveEnum();
9015 defer if (!union_originally) gpa.free(seen_fields);9018 defer if (!union_originally) gpa.free(seen_fields);
9016 if (union_originally) seen_union_fields = seen_fields;9019 if (union_originally) seen_union_fields = seen_fields;
9017 mem.set(?Module.SwitchProngSrc, seen_fields, null);9020 mem.set(?Module.SwitchProngSrc, seen_fields, null);
...@@ -9607,6 +9610,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9607,6 +9610,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9607 }9610 }
96089611
9609 if (scalar_cases_len + multi_cases_len == 0) {9612 if (scalar_cases_len + multi_cases_len == 0) {
9613 if (empty_enum) {
9614 return Air.Inst.Ref.void_value;
9615 }
9610 if (special_prong == .none) {9616 if (special_prong == .none) {
9611 return sema.fail(block, src, "switch must handle all possibilities", .{});9617 return sema.fail(block, src, "switch must handle all possibilities", .{});
9612 }9618 }
...@@ -16690,43 +16696,39 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in...@@ -16690,43 +16696,39 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
1669016696
16691 // Fields16697 // Fields
16692 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));16698 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
16693 if (fields_len > 0) {16699 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16694 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);16700 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
16695 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{16701 .ty = enum_obj.tag_ty,
16696 .ty = enum_obj.tag_ty,16702 .mod = mod,
16697 .mod = mod,16703 });
16698 });
16699
16700 var i: usize = 0;
16701 while (i < fields_len) : (i += 1) {
16702 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16703 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16704 // TODO use reflection instead of magic numbers here
16705 // name: []const u8
16706 const name_val = field_struct_val[0];
16707 // value: comptime_int
16708 const value_val = field_struct_val[1];
16709
16710 const field_name = try name_val.toAllocatedBytes(
16711 Type.initTag(.const_slice_u8),
16712 new_decl_arena_allocator,
16713 sema.mod,
16714 );
1671516704
16716 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);16705 var i: usize = 0;
16717 if (gop.found_existing) {16706 while (i < fields_len) : (i += 1) {
16718 // TODO: better source location16707 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16719 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});16708 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16720 }16709 // TODO use reflection instead of magic numbers here
16710 // name: []const u8
16711 const name_val = field_struct_val[0];
16712 // value: comptime_int
16713 const value_val = field_struct_val[1];
16714
16715 const field_name = try name_val.toAllocatedBytes(
16716 Type.initTag(.const_slice_u8),
16717 new_decl_arena_allocator,
16718 sema.mod,
16719 );
1672116720
16722 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);16721 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
16723 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{16722 if (gop.found_existing) {
16724 .ty = enum_obj.tag_ty,16723 // TODO: better source location
16725 .mod = mod,16724 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});
16726 });
16727 }16725 }
16728 } else {16726
16729 return sema.fail(block, src, "enums must have at least one field", .{});16727 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);
16728 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
16729 .ty = enum_obj.tag_ty,
16730 .mod = mod,
16731 });
16730 }16732 }
1673116733
16732 try new_decl.finalizeNewArena(&new_decl_arena);16734 try new_decl.finalizeNewArena(&new_decl_arena);
...@@ -16851,58 +16853,54 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in...@@ -16851,58 +16853,54 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
16851 }16853 }
1685216854
16853 // Fields16855 // Fields
16854 if (fields_len > 0) {16856 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16855 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
1685616857
16857 var i: usize = 0;16858 var i: usize = 0;
16858 while (i < fields_len) : (i += 1) {16859 while (i < fields_len) : (i += 1) {
16859 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);16860 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16860 const field_struct_val = elem_val.castTag(.aggregate).?.data;16861 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16861 // TODO use reflection instead of magic numbers here16862 // TODO use reflection instead of magic numbers here
16862 // name: []const u816863 // name: []const u8
16863 const name_val = field_struct_val[0];16864 const name_val = field_struct_val[0];
16864 // field_type: type,16865 // field_type: type,
16865 const field_type_val = field_struct_val[1];16866 const field_type_val = field_struct_val[1];
16866 // alignment: comptime_int,16867 // alignment: comptime_int,
16867 const alignment_val = field_struct_val[2];16868 const alignment_val = field_struct_val[2];
16868
16869 const field_name = try name_val.toAllocatedBytes(
16870 Type.initTag(.const_slice_u8),
16871 new_decl_arena_allocator,
16872 sema.mod,
16873 );
1687416869
16875 if (enum_field_names) |set| {16870 const field_name = try name_val.toAllocatedBytes(
16876 set.putAssumeCapacity(field_name, {});16871 Type.initTag(.const_slice_u8),
16877 }16872 new_decl_arena_allocator,
16873 sema.mod,
16874 );
1687816875
16879 if (tag_ty_field_names) |*names| {16876 if (enum_field_names) |set| {
16880 const enum_has_field = names.orderedRemove(field_name);16877 set.putAssumeCapacity(field_name, {});
16881 if (!enum_has_field) {16878 }
16882 const msg = msg: {
16883 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
16884 errdefer msg.destroy(sema.gpa);
16885 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
16886 break :msg msg;
16887 };
16888 return sema.failWithOwnedErrorMsg(msg);
16889 }
16890 }
1689116879
16892 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);16880 if (tag_ty_field_names) |*names| {
16893 if (gop.found_existing) {16881 const enum_has_field = names.orderedRemove(field_name);
16894 // TODO: better source location16882 if (!enum_has_field) {
16895 return sema.fail(block, src, "duplicate union field {s}", .{field_name});16883 const msg = msg: {
16884 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
16885 errdefer msg.destroy(sema.gpa);
16886 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
16887 break :msg msg;
16888 };
16889 return sema.failWithOwnedErrorMsg(msg);
16896 }16890 }
16891 }
1689716892
16898 var buffer: Value.ToTypeBuffer = undefined;16893 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
16899 gop.value_ptr.* = .{16894 if (gop.found_existing) {
16900 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),16895 // TODO: better source location
16901 .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)),16896 return sema.fail(block, src, "duplicate union field {s}", .{field_name});
16902 };
16903 }16897 }
16904 } else {16898
16905 return sema.fail(block, src, "unions must have at least one field", .{});16899 var buffer: Value.ToTypeBuffer = undefined;
16900 gop.value_ptr.* = .{
16901 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),
16902 .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)),
16903 };
16906 }16904 }
1690716905
16908 if (tag_ty_field_names) |names| {16906 if (tag_ty_field_names) |names| {
...@@ -28146,10 +28144,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -28146,10 +28144,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
28146 extra_index = decls_it.extra_index;28144 extra_index = decls_it.extra_index;
2814728145
28148 const body = zir.extra[extra_index..][0..body_len];28146 const body = zir.extra[extra_index..][0..body_len];
28149 if (fields_len == 0) {
28150 assert(body.len == 0);
28151 return;
28152 }
28153 extra_index += body.len;28147 extra_index += body.len;
2815428148
28155 const decl = mod.declPtr(decl_index);28149 const decl = mod.declPtr(decl_index);
...@@ -28237,6 +28231,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -28237,6 +28231,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
28237 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;28231 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
28238 }28232 }
2823928233
28234 if (fields_len == 0) {
28235 return;
28236 }
28237
28240 const bits_per_field = 4;28238 const bits_per_field = 4;
28241 const fields_per_u32 = 32 / bits_per_field;28239 const fields_per_u32 = 32 / bits_per_field;
28242 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;28240 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
...@@ -28772,7 +28770,9 @@ pub fn typeHasOnePossibleValue(...@@ -28772,7 +28770,9 @@ pub fn typeHasOnePossibleValue(
28772 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;28770 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
28773 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse28771 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
28774 return null;28772 return null;
28775 const only_field = union_obj.fields.values()[0];28773 const fields = union_obj.fields.values();
28774 if (fields.len == 0) return Value.initTag(.empty_struct_value);
28775 const only_field = fields[0];
28776 if (only_field.ty.eql(resolved_ty, sema.mod)) {28776 if (only_field.ty.eql(resolved_ty, sema.mod)) {
28777 const msg = try Module.ErrorMsg.create(28777 const msg = try Module.ErrorMsg.create(
28778 sema.gpa,28778 sema.gpa,
src/print_zir.zig+10-5
...@@ -1443,7 +1443,7 @@ const Writer = struct {...@@ -1443,7 +1443,7 @@ const Writer = struct {
1443 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);1443 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
14441444
1445 if (decls_len == 0) {1445 if (decls_len == 0) {
1446 try stream.writeAll("{}, ");1446 try stream.writeAll("{}");
1447 } else {1447 } else {
1448 const prev_parent_decl_node = self.parent_decl_node;1448 const prev_parent_decl_node = self.parent_decl_node;
1449 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);1449 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
...@@ -1454,15 +1454,20 @@ const Writer = struct {...@@ -1454,15 +1454,20 @@ const Writer = struct {
1454 extra_index = try self.writeDecls(stream, decls_len, extra_index);1454 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1455 self.indent -= 2;1455 self.indent -= 2;
1456 try stream.writeByteNTimes(' ', self.indent);1456 try stream.writeByteNTimes(' ', self.indent);
1457 try stream.writeAll("}, ");1457 try stream.writeAll("}");
1458 }1458 }
14591459
1460 assert(fields_len != 0);
1461
1462 if (tag_type_ref != .none) {1460 if (tag_type_ref != .none) {
1463 try self.writeInstRef(stream, tag_type_ref);
1464 try stream.writeAll(", ");1461 try stream.writeAll(", ");
1462 try self.writeInstRef(stream, tag_type_ref);
1463 }
1464
1465 if (fields_len == 0) {
1466 try stream.writeAll("})");
1467 try self.writeSrcNode(stream, src_node);
1468 return;
1465 }1469 }
1470 try stream.writeAll(", ");
14661471
1467 const body = self.code.extra[extra_index..][0..body_len];1472 const body = self.code.extra[extra_index..][0..body_len];
1468 extra_index += body.len;1473 extra_index += body.len;
src/type.zig+4-1
...@@ -2488,7 +2488,7 @@ pub const Type = extern union {...@@ -2488,7 +2488,7 @@ pub const Type = extern union {
2488 },2488 },
2489 .union_safety_tagged, .union_tagged => {2489 .union_safety_tagged, .union_tagged => {
2490 const union_obj = ty.cast(Payload.Union).?.data;2490 const union_obj = ty.cast(Payload.Union).?.data;
2491 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {2491 if (union_obj.fields.count() > 0 and try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {
2492 return true;2492 return true;
2493 }2493 }
2494 if (sema_kit) |sk| {2494 if (sema_kit) |sk| {
...@@ -3113,6 +3113,9 @@ pub const Type = extern union {...@@ -3113,6 +3113,9 @@ pub const Type = extern union {
3113 .sema_kit => unreachable, // handled above3113 .sema_kit => unreachable, // handled above
3114 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },3114 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
3115 };3115 };
3116 if (union_obj.fields.count() == 0) {
3117 return AbiAlignmentAdvanced{ .scalar = @boolToInt(union_obj.layout == .Extern) };
3118 }
31163119
3117 var max_align: u32 = 0;3120 var max_align: u32 = 0;
3118 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);3121 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);
test/behavior.zig+1
...@@ -167,6 +167,7 @@ test {...@@ -167,6 +167,7 @@ test {
167 if (builtin.zig_backend != .stage1) {167 if (builtin.zig_backend != .stage1) {
168 _ = @import("behavior/decltest.zig");168 _ = @import("behavior/decltest.zig");
169 _ = @import("behavior/packed_struct_explicit_backing_int.zig");169 _ = @import("behavior/packed_struct_explicit_backing_int.zig");
170 _ = @import("behavior/empty_union.zig");
170 }171 }
171172
172 if (builtin.os.tag != .wasi) {173 if (builtin.os.tag != .wasi) {
test/behavior/empty_union.zig created+54
...@@ -0,0 +1,54 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4
5test "switch on empty enum" {
6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8
9 const E = enum {};
10 var e: E = undefined;
11 switch (e) {}
12}
13
14test "switch on empty enum with a specified tag type" {
15 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
17
18 const E = enum(u8) {};
19 var e: E = undefined;
20 switch (e) {}
21}
22
23test "switch on empty auto numbered tagged union" {
24 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
27
28 const U = union(enum(u8)) {};
29 var u: U = undefined;
30 switch (u) {}
31}
32
33test "switch on empty tagged union" {
34 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
37
38 const E = enum {};
39 const U = union(E) {};
40 var u: U = undefined;
41 switch (u) {}
42}
43
44test "empty union" {
45 const U = union {};
46 try expect(@sizeOf(U) == 0);
47 try expect(@alignOf(U) == 0);
48}
49
50test "empty extern union" {
51 const U = extern union {};
52 try expect(@sizeOf(U) == 0);
53 try expect(@alignOf(U) == 1);
54}
test/cases/compile_errors/enum_with_0_fields.zig deleted-7
...@@ -1,7 +0,0 @@
1const Foo = enum {};
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:13: error: enum declarations must have at least one tag
test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig deleted-18
...@@ -1,18 +0,0 @@
1const Tag = @Type(.{
2 .Enum = .{
3 .layout = .Auto,
4 .tag_type = u1,
5 .fields = &.{},
6 .decls = &.{},
7 .is_exhaustive = true,
8 },
9});
10export fn entry() void {
11 _ = @intToEnum(Tag, 0);
12}
13
14// error
15// backend=stage2
16// target=native
17//
18// :1:13: error: enums must have at least one field
test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig deleted-17
...@@ -1,17 +0,0 @@
1const Untagged = @Type(.{
2 .Union = .{
3 .layout = .Auto,
4 .tag_type = null,
5 .fields = &.{},
6 .decls = &.{},
7 },
8});
9export fn entry() void {
10 _ = Untagged{};
11}
12
13// error
14// backend=stage2
15// target=native
16//
17// :1:18: error: unions must have at least one field
test/cases/compile_errors/union_fields_with_value_assignments.zig deleted-7
...@@ -1,7 +0,0 @@
1const Foo = union {};
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:13: error: union declarations must have at least one tag
test/cases/compile_errors/union_with_0_fields.zig deleted-7
...@@ -1,7 +0,0 @@
1const Foo = union {};
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:13: error: union declarations must have at least one tag
test/cases/compile_errors/using_invalid_types_in_function_call_raises_an_error.zig deleted-11
...@@ -1,11 +0,0 @@
1const MenuEffect = enum {};
2fn func(effect: MenuEffect) void { _ = effect; }
3export fn entry() void {
4 func(MenuEffect.ThisDoesNotExist);
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :1:20: error: enum declarations must have at least one tag
test/stage2/cbe.zig-9
...@@ -704,15 +704,6 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -704,15 +704,6 @@ pub fn addCases(ctx: *TestContext) !void {
704 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",704 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",
705 });705 });
706706
707 case.addError(
708 \\const E1 = enum {};
709 \\export fn foo() void {
710 \\ _ = E1.a;
711 \\}
712 , &.{
713 ":1:12: error: enum declarations must have at least one tag",
714 });
715
716 case.addError(707 case.addError(
717 \\const E1 = enum { a, b, _ };708 \\const E1 = enum { a, b, _ };
718 \\export fn foo() void {709 \\export fn foo() void {