authorgravatar for justus@klausecker.deJustus Klausecker <justus@klausecker.de> 2026-06-02 16:36:15+02:00
committergravatar for justus@klausecker.deJustus Klausecker <justus@klausecker.de> 2026-07-17 00:02:41+02:00
log9aeac329a25ddf43bf3afdfe8c381682226dafdf
tree7060de5e6a6656207e82d21c2a9297067a1285f5
parente44e927d33d37c4417b9abb9a207b35fd25cd353

Sema: require `noreturn` as backing integer of empty enums

Empty enums are uninstantiable, so their backing integer should be too. This avoids a bunch of weird special cases during semantic analysis. If you were previously using `enum {}`, your code should continue to work fine. If you were previously using `enum(uN) {}` (where `uN` is any integer type), you'll probably want to use `enum(uN) { _ }` instead.

21 files changed, 137 insertions(+), 100 deletions(-)

doc/langref.html.in+1-1
...@@ -2401,7 +2401,7 @@ or...@@ -2401,7 +2401,7 @@ or
2401 {#header_open|enum#}2401 {#header_open|enum#}
2402 {#code|test_enums.zig#}2402 {#code|test_enums.zig#}
24032403
2404 {#see_also|@typeInfo|@tagName|@sizeOf#}2404 {#see_also|@typeInfo|@tagName|@sizeOf|noreturn#}
24052405
2406 {#header_open|extern enum#}2406 {#header_open|extern enum#}
2407 <p>2407 <p>
doc/langref/test_enums.zig+6
...@@ -111,4 +111,10 @@ test "@tagName" {...@@ -111,4 +111,10 @@ test "@tagName" {
111 try expectEqualStrings(@tagName(Small.three), "three");111 try expectEqualStrings(@tagName(Small.three), "three");
112}112}
113113
114// Empty enums are uninstantiable, their tag type is always noreturn.
115const Empty = enum {};
116test "empty enum" {
117 try expectEqual(noreturn, @typeInfo(Empty).@"enum".tag_type);
118}
119
114// test120// test
lib/std/meta.zig+4-2
...@@ -408,7 +408,8 @@ pub fn FieldEnum(comptime T: type) type {...@@ -408,7 +408,8 @@ pub fn FieldEnum(comptime T: type) type {
408 else => {},408 else => {},
409 }409 }
410410
411 const IntTag = std.math.IntFittingRange(0, field_names.len -| 1);411 if (field_names.len == 0) return enum {};
412 const IntTag = std.math.IntFittingRange(0, field_names.len - 1);
412 return @Enum(IntTag, .exhaustive, field_names, &std.simd.iota(IntTag, field_names.len));413 return @Enum(IntTag, .exhaustive, field_names, &std.simd.iota(IntTag, field_names.len));
413}414}
414415
...@@ -469,7 +470,8 @@ test FieldEnum {...@@ -469,7 +470,8 @@ test FieldEnum {
469470
470pub fn DeclEnum(comptime T: type) type {471pub fn DeclEnum(comptime T: type) type {
471 const decl_names = declarations(T);472 const decl_names = declarations(T);
472 const IntTag = std.math.IntFittingRange(0, decl_names.len -| 1);473 if (decl_names.len == 0) return enum {};
474 const IntTag = std.math.IntFittingRange(0, decl_names.len - 1);
473 return @Enum(IntTag, .exhaustive, decl_names, &std.simd.iota(IntTag, decl_names.len));475 return @Enum(IntTag, .exhaustive, decl_names, &std.simd.iota(IntTag, decl_names.len));
474}476}
475477
lib/std/zig.zig-2
...@@ -906,7 +906,6 @@ pub const SimpleComptimeReason = enum(u32) {...@@ -906,7 +906,6 @@ pub const SimpleComptimeReason = enum(u32) {
906 slice_single_item_ptr_bounds,906 slice_single_item_ptr_bounds,
907 stored_to_comptime_field,907 stored_to_comptime_field,
908 stored_to_comptime_var,908 stored_to_comptime_var,
909 casted_to_comptime_enum,
910 casted_to_comptime_int,909 casted_to_comptime_int,
911 casted_to_comptime_float,910 casted_to_comptime_float,
912 std_lang_decl,911 std_lang_decl,
...@@ -989,7 +988,6 @@ pub const SimpleComptimeReason = enum(u32) {...@@ -989,7 +988,6 @@ pub const SimpleComptimeReason = enum(u32) {
989 .slice_single_item_ptr_bounds => "slice of single-item pointer must have comptime-known bounds",988 .slice_single_item_ptr_bounds => "slice of single-item pointer must have comptime-known bounds",
990 .stored_to_comptime_field => "value stored to a comptime field must be comptime-known",989 .stored_to_comptime_field => "value stored to a comptime field must be comptime-known",
991 .stored_to_comptime_var => "value stored to a comptime variable must be comptime-known",990 .stored_to_comptime_var => "value stored to a comptime variable must be comptime-known",
992 .casted_to_comptime_enum => "value casted to enum with 'comptime_int' tag type must be comptime-known",
993 .casted_to_comptime_int => "value casted to 'comptime_int' must be comptime-known",991 .casted_to_comptime_int => "value casted to 'comptime_int' must be comptime-known",
994 .casted_to_comptime_float => "value casted to 'comptime_float' must be comptime-known",992 .casted_to_comptime_float => "value casted to 'comptime_float' must be comptime-known",
995 .std_lang_decl => "'std.lang' declaration values must be comptime-known",993 .std_lang_decl => "'std.lang' declaration values must be comptime-known",
lib/std/zig/parser_test.zig+1-1
...@@ -1120,7 +1120,7 @@ test "zig fmt: empty enum decls" {...@@ -1120,7 +1120,7 @@ test "zig fmt: empty enum decls" {
1120 \\const A = enum {};1120 \\const A = enum {};
1121 \\const B = enum(u32) {};1121 \\const B = enum(u32) {};
1122 \\const C = extern enum(c_int) {};1122 \\const C = extern enum(c_int) {};
1123 \\const D = packed enum(u8) {};1123 \\const D = packed enum(noreturn) {};
1124 \\1124 \\
1125 );1125 );
1126}1126}
src/InternPool.zig+2-7
...@@ -5040,7 +5040,6 @@ pub const Tag = enum(u8) {...@@ -5040,7 +5040,6 @@ pub const Tag = enum(u8) {
5040 /// The set of values that are encoded this way is:5040 /// The set of values that are encoded this way is:
5041 /// * An array or vector which has length 0.5041 /// * An array or vector which has length 0.
5042 /// * A struct which has all fields comptime-known.5042 /// * A struct which has all fields comptime-known.
5043 /// * An empty enum or union. TODO: this value's existence is strange, because such a type in reality has no values. See #15909
5044 /// data is Index of the type, which is known to be zero bits at runtime.5043 /// data is Index of the type, which is known to be zero bits at runtime.
5045 only_possible_value,5044 only_possible_value,
5046 /// data is extra index to Key.Union.5045 /// data is extra index to Key.Union.
...@@ -7740,12 +7739,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -7740,12 +7739,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
7740 }),7739 }),
77417740
7742 .enum_tag => |enum_tag| {7741 .enum_tag => |enum_tag| {
7743 assert(ip.isEnumType(enum_tag.ty));7742 const enum_obj = ip.loadEnumType(enum_tag.ty);
7744 switch (ip.indexToKey(enum_tag.ty)) {7743 assert(ip.typeOf(enum_tag.int) == enum_obj.int_tag_type);
7745 .simple_type => assert(ip.isIntegerType(ip.typeOf(enum_tag.int))),
7746 .enum_type => assert(ip.typeOf(enum_tag.int) == ip.loadEnumType(enum_tag.ty).int_tag_type),
7747 else => unreachable,
7748 }
7749 items.appendAssumeCapacity(.{7744 items.appendAssumeCapacity(.{
7750 .tag = .enum_tag,7745 .tag = .enum_tag,
7751 .data = try addExtra(extra, enum_tag),7746 .data = try addExtra(extra, enum_tag),
src/Sema.zig+2-27
...@@ -7854,14 +7854,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -7854,14 +7854,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
7854 };7854 };
7855 const enum_tag_ty = sema.typeOf(enum_tag);7855 const enum_tag_ty = sema.typeOf(enum_tag);
7856 const int_tag_ty = enum_tag_ty.intTagType(zcu);7856 const int_tag_ty = enum_tag_ty.intTagType(zcu);
78577857 assert(int_tag_ty.classify(zcu) != .no_possible_value);
7858 // TODO: use correct solution
7859 // https://github.com/ziglang/zig/issues/15909
7860 if (enum_tag_ty.enumFieldCount(zcu) == 0 and !enum_tag_ty.isNonexhaustiveEnum(zcu)) {
7861 return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{f}'", .{
7862 enum_tag_ty.fmt(pt),
7863 });
7864 }
78657858
7866 if (sema.resolveValue(enum_tag)) |enum_tag_val| {7859 if (sema.resolveValue(enum_tag)) |enum_tag_val| {
7867 if (enum_tag_val.isUndef(zcu)) return pt.undefRef(int_tag_ty);7860 if (enum_tag_val.isUndef(zcu)) return pt.undefRef(int_tag_ty);
...@@ -7910,10 +7903,6 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -7910,10 +7903,6 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
7910 return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern());7903 return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern());
7911 }7904 }
79127905
7913 if (dest_ty.intTagType(zcu).zigTypeTag(zcu) == .comptime_int) {
7914 return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_enum });
7915 }
7916
7917 if (try dest_ty.onePossibleValue(pt)) |opv| {7906 if (try dest_ty.onePossibleValue(pt)) |opv| {
7918 if (block.wantSafety()) {7907 if (block.wantSafety()) {
7919 // The operand is runtime-known but the result is comptime-known. In7908 // The operand is runtime-known but the result is comptime-known. In
...@@ -9940,13 +9929,6 @@ fn analyzeSwitchBlock(...@@ -9940,13 +9929,6 @@ fn analyzeSwitchBlock(
9940 operand_ty.containerLayout(zcu) != .@"packed";9929 operand_ty.containerLayout(zcu) != .@"packed";
9941 const err_set = operand_ty.zigTypeTag(zcu) == .error_set;9930 const err_set = operand_ty.zigTypeTag(zcu) == .error_set;
99429931
9943 if (item_ty.zigTypeTag(zcu) == .@"enum" and
9944 validated_switch.seen_enum_fields.len == 0 and
9945 !operand_ty.isNonexhaustiveEnum(zcu))
9946 {
9947 return .void_value; // switch on empty enum/union
9948 }
9949
9950 const cond_ref = switch (operand) {9932 const cond_ref = switch (operand) {
9951 .simple => |s| s.cond,9933 .simple => |s| s.cond,
9952 .loop => |l| l.init_cond,9934 .loop => |l| l.init_cond,
...@@ -19567,14 +19549,6 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -19567,14 +19549,6 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
19567 operand_ty.fmt(pt),19549 operand_ty.fmt(pt),
19568 }),19550 }),
19569 };19551 };
19570 if (enum_ty.enumFieldCount(zcu) == 0) {
19571 // TODO I don't think this is the correct way to handle this but
19572 // it prevents a crash.
19573 // https://github.com/ziglang/zig/issues/15909
19574 return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{f}'", .{
19575 enum_ty.fmt(pt),
19576 });
19577 }
19578 const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src);19552 const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src);
19579 if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| {19553 if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| {
19580 const field_index = enum_ty.enumTagFieldIndex(val, zcu) orelse {19554 const field_index = enum_ty.enumTagFieldIndex(val, zcu) orelse {
...@@ -33985,6 +33959,7 @@ fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {...@@ -33985,6 +33959,7 @@ fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
33985 // The `tagValueIndex` function call below relies on the type being the integer tag type.33959 // The `tagValueIndex` function call below relies on the type being the integer tag type.
33986 // `getCoerced` assumes the value will fit the new type.33960 // `getCoerced` assumes the value will fit the new type.
33987 const int_tag_ty: Type = .fromInterned(enum_type.int_tag_type);33961 const int_tag_ty: Type = .fromInterned(enum_type.int_tag_type);
33962 if (int_tag_ty.classify(zcu) == .no_possible_value) return false;
33988 if (!int.intFitsInType(int_tag_ty, null, zcu)) return false;33963 if (!int.intFitsInType(int_tag_ty, null, zcu)) return false;
33989 const int_coerced = try pt.getCoerced(int, int_tag_ty);33964 const int_coerced = try pt.getCoerced(int, int_tag_ty);
33990 return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null;33965 return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null;
src/Sema/type_resolution.zig+22-6
...@@ -1325,15 +1325,31 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {...@@ -1325,15 +1325,31 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
1325 const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index);1325 const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index);
1326 break :ty try sema.analyzeAsType(&block, tag_type_src, .enum_int_tag_type, type_ref);1326 break :ty try sema.analyzeAsType(&block, tag_type_src, .enum_int_tag_type, type_ref);
1327 };1327 };
1328 const empty_exhaustive = enum_obj.field_names.len == 0 and !enum_obj.nonexhaustive;
1328 const int_tag_ty: Type = if (explicit_int_tag_ty) |int_tag_ty| ty: {1329 const int_tag_ty: Type = if (explicit_int_tag_ty) |int_tag_ty| ty: {
1329 if (int_tag_ty.zigTypeTag(zcu) != .int) return sema.fail(1330 switch (int_tag_ty.zigTypeTag(zcu)) {
1330 &block,1331 .int => if (empty_exhaustive) return sema.fail(
1331 block.src(.container_arg),1332 &block,
1332 "expected integer tag type, found '{f}'",1333 block.src(.container_arg),
1333 .{int_tag_ty.fmt(pt)},1334 "empty exhaustive enums must be backed by 'noreturn'",
1334 );1335 .{},
1336 ),
1337 .noreturn => if (!empty_exhaustive) return sema.fail(
1338 &block,
1339 block.src(.container_arg),
1340 "non-empty enums cannot be backed by 'noreturn'",
1341 .{},
1342 ),
1343 else => return sema.fail(
1344 &block,
1345 block.src(.container_arg),
1346 "expected integer tag type, found '{f}'",
1347 .{int_tag_ty.fmt(pt)},
1348 ),
1349 }
1335 break :ty int_tag_ty;1350 break :ty int_tag_ty;
1336 } else ty: {1351 } else ty: {
1352 if (empty_exhaustive) break :ty .noreturn;
1337 // Infer the int tag type from the field count1353 // Infer the int tag type from the field count
1338 const bits = Type.smallestUnsignedBits(enum_obj.field_names.len -| 1);1354 const bits = Type.smallestUnsignedBits(enum_obj.field_names.len -| 1);
1339 break :ty try pt.intType(.unsigned, bits);1355 break :ty try pt.intType(.unsigned, bits);
src/Type.zig+9-3
...@@ -3058,9 +3058,15 @@ pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason {...@@ -3058,9 +3058,15 @@ pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason {
3058 .one, .many, .c => .pointer,3058 .one, .many, .c => .pointer,
3059 },3059 },
30603060
3061 .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_mode) {3061 .@"enum" => {
3062 .explicit => null,3062 const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern());
3063 .auto => .{ .enum_inferred_int_tag = ty },3063 return switch (enum_obj.int_tag_mode) {
3064 .explicit => if (enum_obj.int_tag_type != .noreturn_type)
3065 null
3066 else
3067 .other,
3068 .auto => .{ .enum_inferred_int_tag = ty },
3069 };
3064 },3070 },
30653071
3066 .@"struct" => switch (ty.containerLayout(zcu)) {3072 .@"struct" => switch (ty.containerLayout(zcu)) {
src/link/Dwarf.zig+1
...@@ -5098,6 +5098,7 @@ fn DeclValEnum(comptime T: type) type {...@@ -5098,6 +5098,7 @@ fn DeclValEnum(comptime T: type) type {
5098 if (min_value == null or min_value.? > value) min_value = value;5098 if (min_value == null or min_value.? > value) min_value = value;
5099 if (max_value == null or max_value.? < value) max_value = value;5099 if (max_value == null or max_value.? < value) max_value = value;
5100 }5100 }
5101 if (fields_len == 0) return enum {};
5101 const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0);5102 const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0);
5102 var field_vals: [fields_len]TagInt = undefined;5103 var field_vals: [fields_len]TagInt = undefined;
5103 for (field_names[0..fields_len], &field_vals) |name, *val| val.* = @field(T, name);5104 for (field_names[0..fields_len], &field_vals) |name, *val| val.* = @field(T, name);
test/behavior/enum.zig-23
...@@ -1451,29 +1451,6 @@ test "comptime @enumFromInt with signed arithmetic" {...@@ -1451,29 +1451,6 @@ test "comptime @enumFromInt with signed arithmetic" {
1451 comptime assert(@intFromEnum(x) == 0);1451 comptime assert(@intFromEnum(x) == 0);
1452}1452}
14531453
1454test "switch on empty enum" {
1455 const E = enum {};
1456 var e: E = undefined;
1457 _ = &e;
1458 switch (e) {}
1459}
1460
1461test "switch on empty enum with a specified tag type" {
1462 const E = enum(u8) {};
1463 var e: E = undefined;
1464 _ = &e;
1465 switch (e) {}
1466}
1467
1468test "empty enum passed as argument" {
1469 const E = enum {
1470 fn f(e: @This()) void {
1471 switch (e) {}
1472 }
1473 };
1474 E.f(@as(E, undefined));
1475}
1476
1477test "enum int tag type uses declaration inside the enum" {1454test "enum int tag type uses declaration inside the enum" {
1478 const static = struct {1455 const static = struct {
1479 const E = enum(E.IntTag) {1456 const E = enum(E.IntTag) {
test/behavior/type.zig+1-1
...@@ -270,7 +270,7 @@ test "Type.Union from empty regular enum" {...@@ -270,7 +270,7 @@ test "Type.Union from empty regular enum" {
270}270}
271271
272test "Type.Union from empty Type.Enum" {272test "Type.Union from empty Type.Enum" {
273 const E = @Enum(u0, .exhaustive, &.{}, &.{});273 const E = @Enum(noreturn, .exhaustive, &.{}, &.{});
274 const U = @Union(.auto, E, &.{}, &.{}, &.{});274 const U = @Union(.auto, E, &.{}, &.{}, &.{});
275 try testing.expectEqual(@typeInfo(U).@"union".field_names.len, 0);275 try testing.expectEqual(@typeInfo(U).@"union".field_names.len, 0);
276}276}
test/cases/compile_errors/enum_noreturn_backing_type.zig created+16
...@@ -0,0 +1,16 @@
1const E1 = enum(u32) {};
2export fn entry1() void {
3 const e: E1 = undefined;
4 _ = e;
5}
6
7const E2 = enum(noreturn) { a, b, c };
8export fn entry2() void {
9 const e: E2 = undefined;
10 _ = e;
11}
12
13// error
14//
15// :1:17: error: empty exhaustive enums must be backed by 'noreturn'
16// :7:17: error: non-empty enums cannot be backed by 'noreturn'
test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig+19-11
...@@ -1,15 +1,23 @@...@@ -1,15 +1,23 @@
1pub const E = enum(u31) { A, B, C };1export fn entry1() void {
2pub const S = extern struct {2 const E = enum(u31) { A, B, C };
3 e: E,3 _ = @sizeOf(extern struct {
4};4 x: E,
5export fn entry() void {5 });
6 const s: S = undefined;6}
7 _ = s;7export fn entry2() void {
8 const E = enum(noreturn) {};
9 _ = @sizeOf(extern struct {
10 x: E,
11 });
8}12}
913
10// error14// error
11//15//
12// :3:8: error: extern structs cannot contain fields of type 'tmp.E'16// :4:12: error: extern structs cannot contain fields of type 'tmp.entry1.E'
13// :1:15: note: enum tag type 'u31' is not extern compatible17// :2:15: note: enum tag type 'u31' is not extern compatible
14// :1:15: note: only integers with 0 or power of two bits are extern compatible18// :2:15: note: only integers with 0 or power of two bits are extern compatible
15// :1:15: note: enum declared here19// :2:15: note: enum declared here
20// :10:12: error: extern structs cannot contain fields of type 'tmp.entry2.E'
21// :8:15: note: enum tag type 'noreturn' is not extern compatible
22// :8:15: note: 'noreturn' is only allowed as a return type
23// :8:15: note: enum declared here
test/cases/compile_errors/initialize_empty_union.zig+2-2
...@@ -1,10 +1,10 @@...@@ -1,10 +1,10 @@
1const EnumInferred = enum {};1const EnumInferred = enum {};
2const EnumExplicit = enum(u8) {};2const EnumExplicit = enum(noreturn) {};
3const EnumNonexhaustive = enum(u8) { _ };3const EnumNonexhaustive = enum(u8) { _ };
44
5const U0 = union {};5const U0 = union {};
6const U1 = union(enum) {};6const U1 = union(enum) {};
7const U2 = union(enum(u8)) {};7const U2 = union(enum(noreturn)) {};
8const U3 = union(EnumInferred) {};8const U3 = union(EnumInferred) {};
9const U4 = union(EnumExplicit) {};9const U4 = union(EnumExplicit) {};
10const U5 = union(EnumNonexhaustive) {};10const U5 = union(EnumNonexhaustive) {};
test/cases/compile_errors/instantiate_empty_enum.zig created+32
...@@ -0,0 +1,32 @@
1const E = enum {};
2
3export fn entry1() void {
4 const e: E = undefined;
5 _ = e;
6}
7
8export fn entry2() void {
9 const e: E = @enumFromInt(@as(u8, undefined));
10 _ = e;
11}
12
13export fn entry3() void {
14 const e: E = .a;
15 _ = e;
16}
17
18export fn entry4() void {
19 const e: E = @enumFromInt(0);
20 _ = e;
21}
22
23// error
24//
25// :4:18: error: expected type 'tmp.E', found '@TypeOf(undefined)'
26// :4:18: note: cannot coerce to uninstantiable type 'tmp.E'
27// :1:11: note: enum declared here
28// :9:31: error: use of undefined value here causes illegal behavior
29// :14:19: error: enum 'tmp.E' has no member named 'a'
30// :1:11: note: enum declared here
31// :19:18: error: enum 'tmp.E' has no tag with value '0'
32// :1:11: note: enum declared here
test/cases/compile_errors/int_from_enum_undefined.zig deleted-11
...@@ -1,11 +0,0 @@
1export fn a() void {
2 const E = enum {};
3 var e: E = undefined;
4 _ = &e;
5 _ = @intFromEnum(e);
6}
7
8// error
9//
10// :5:22: error: cannot use @intFromEnum on empty enum 'tmp.a.E'
11// :2:15: note: enum declared here
test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig+8
...@@ -81,6 +81,12 @@ export fn entry15() void {...@@ -81,6 +81,12 @@ export fn entry15() void {
81 x: *const u32,81 x: *const u32,
82 });82 });
83}83}
84export fn entry16() void {
85 const E = enum(noreturn) {};
86 _ = @sizeOf(packed struct {
87 x: E,
88 });
89}
8490
85// error91// error
86//92//
...@@ -114,3 +120,5 @@ export fn entry15() void {...@@ -114,3 +120,5 @@ export fn entry15() void {
114// :81:12: error: packed structs cannot contain fields of type '*const u32'120// :81:12: error: packed structs cannot contain fields of type '*const u32'
115// :81:12: note: pointers cannot be directly bitpacked121// :81:12: note: pointers cannot be directly bitpacked
116// :81:12: note: consider using 'usize' and '@intFromPtr'122// :81:12: note: consider using 'usize' and '@intFromPtr'
123// :87:12: error: packed structs cannot contain fields of type 'tmp.entry16.E'
124// :87:12: note: type does not have a bit-packed representation
test/cases/compile_errors/packed_union_with_fields_of_not_allowed_types.zig+8
...@@ -10,6 +10,12 @@ export fn entry1() void {...@@ -10,6 +10,12 @@ export fn entry1() void {
10 x: *const u32,10 x: *const u32,
11 });11 });
12}12}
13export fn entry2() void {
14 const E = enum(noreturn) {};
15 _ = @sizeOf(packed union {
16 x: E,
17 });
18}
1319
14// error20// error
15//21//
...@@ -19,3 +25,5 @@ export fn entry1() void {...@@ -19,3 +25,5 @@ export fn entry1() void {
19// :10:12: error: packed unions cannot contain fields of type '*const u32'25// :10:12: error: packed unions cannot contain fields of type '*const u32'
20// :10:12: note: pointers cannot be directly bitpacked26// :10:12: note: pointers cannot be directly bitpacked
21// :10:12: note: consider using 'usize' and '@intFromPtr'27// :10:12: note: consider using 'usize' and '@intFromPtr'
28// :16:12: error: packed unions cannot contain fields of type 'tmp.entry2.E'
29// :16:12: note: type does not have a bit-packed representation
test/cases/compile_errors/reify_type_for_tagged_union_with_no_enum_fields.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const Tag = @Enum(u0, .exhaustive, &.{}, &.{});1const Tag = @Enum(noreturn, .exhaustive, &.{}, &.{});
2const Tagged = @Union(.auto, Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &@splat(.{}));2const Tagged = @Union(.auto, Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &@splat(.{}));
3export fn entry() void {3export fn entry() void {
4 const tagged: Tagged = undefined;4 const tagged: Tagged = undefined;
test/cases/compile_errors/sizeof_alignof_empty_union.zig+2-2
...@@ -1,10 +1,10 @@...@@ -1,10 +1,10 @@
1const EnumInferred = enum {};1const EnumInferred = enum {};
2const EnumExplicit = enum(u8) {};2const EnumExplicit = enum(noreturn) {};
3const EnumNonexhaustive = enum(u8) { _ };3const EnumNonexhaustive = enum(u8) { _ };
44
5const U0 = union {};5const U0 = union {};
6const U1 = union(enum) {};6const U1 = union(enum) {};
7const U2 = union(enum(u8)) {};7const U2 = union(enum(noreturn)) {};
8const U3 = union(EnumInferred) {};8const U3 = union(EnumInferred) {};
9const U4 = union(EnumExplicit) {};9const U4 = union(EnumExplicit) {};
10const U5 = union(EnumNonexhaustive) {};10const U5 = union(EnumNonexhaustive) {};