| author | |
| committer | |
| log | 9aeac329a25ddf43bf3afdfe8c381682226dafdf |
| tree | 7060de5e6a6656207e82d21c2a9297067a1285f5 |
| parent | e44e927d33d37c4417b9abb9a207b35fd25cd353 |
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 | 2401 | {#header_open|enum#} |
| 2402 | 2402 | {#code|test_enums.zig#} |
| 2403 | 2403 | |
| 2404 | {#see_also|@typeInfo|@tagName|@sizeOf#} | |
| 2404 | {#see_also|@typeInfo|@tagName|@sizeOf|noreturn#} | |
| 2405 | 2405 | |
| 2406 | 2406 | {#header_open|extern enum#} |
| 2407 | 2407 | <p> |
doc/langref/test_enums.zig+6| ... | ... | @@ -111,4 +111,10 @@ test "@tagName" { |
| 111 | 111 | try expectEqualStrings(@tagName(Small.three), "three"); |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | // Empty enums are uninstantiable, their tag type is always noreturn. | |
| 115 | const Empty = enum {}; | |
| 116 | test "empty enum" { | |
| 117 | try expectEqual(noreturn, @typeInfo(Empty).@"enum".tag_type); | |
| 118 | } | |
| 119 | ||
| 114 | 120 | // test |
lib/std/meta.zig+4-2| ... | ... | @@ -408,7 +408,8 @@ pub fn FieldEnum(comptime T: type) type { |
| 408 | 408 | else => {}, |
| 409 | 409 | } |
| 410 | 410 | |
| 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 | 413 | return @Enum(IntTag, .exhaustive, field_names, &std.simd.iota(IntTag, field_names.len)); |
| 413 | 414 | } |
| 414 | 415 | |
| ... | ... | @@ -469,7 +470,8 @@ test FieldEnum { |
| 469 | 470 | |
| 470 | 471 | pub fn DeclEnum(comptime T: type) type { |
| 471 | 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 | 475 | return @Enum(IntTag, .exhaustive, decl_names, &std.simd.iota(IntTag, decl_names.len)); |
| 474 | 476 | } |
| 475 | 477 |
lib/std/zig.zig-2| ... | ... | @@ -906,7 +906,6 @@ pub const SimpleComptimeReason = enum(u32) { |
| 906 | 906 | slice_single_item_ptr_bounds, |
| 907 | 907 | stored_to_comptime_field, |
| 908 | 908 | stored_to_comptime_var, |
| 909 | casted_to_comptime_enum, | |
| 910 | 909 | casted_to_comptime_int, |
| 911 | 910 | casted_to_comptime_float, |
| 912 | 911 | std_lang_decl, |
| ... | ... | @@ -989,7 +988,6 @@ pub const SimpleComptimeReason = enum(u32) { |
| 989 | 988 | .slice_single_item_ptr_bounds => "slice of single-item pointer must have comptime-known bounds", |
| 990 | 989 | .stored_to_comptime_field => "value stored to a comptime field must be comptime-known", |
| 991 | 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 | 991 | .casted_to_comptime_int => "value casted to 'comptime_int' must be comptime-known", |
| 994 | 992 | .casted_to_comptime_float => "value casted to 'comptime_float' must be comptime-known", |
| 995 | 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 | 1120 | \\const A = enum {}; |
| 1121 | 1121 | \\const B = enum(u32) {}; |
| 1122 | 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 | 5040 | /// The set of values that are encoded this way is: |
| 5041 | 5041 | /// * An array or vector which has length 0. |
| 5042 | 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 | 5043 | /// data is Index of the type, which is known to be zero bits at runtime. |
| 5045 | 5044 | only_possible_value, |
| 5046 | 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 | 7739 | }), |
| 7741 | 7740 | |
| 7742 | 7741 | .enum_tag => |enum_tag| { |
| 7743 | assert(ip.isEnumType(enum_tag.ty)); | |
| 7744 | switch (ip.indexToKey(enum_tag.ty)) { | |
| 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 | } | |
| 7742 | const enum_obj = ip.loadEnumType(enum_tag.ty); | |
| 7743 | assert(ip.typeOf(enum_tag.int) == enum_obj.int_tag_type); | |
| 7749 | 7744 | items.appendAssumeCapacity(.{ |
| 7750 | 7745 | .tag = .enum_tag, |
| 7751 | 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 | 7854 | }; |
| 7855 | 7855 | const enum_tag_ty = sema.typeOf(enum_tag); |
| 7856 | 7856 | const int_tag_ty = enum_tag_ty.intTagType(zcu); |
| 7857 | ||
| 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 | } | |
| 7857 | assert(int_tag_ty.classify(zcu) != .no_possible_value); | |
| 7865 | 7858 | |
| 7866 | 7859 | if (sema.resolveValue(enum_tag)) |enum_tag_val| { |
| 7867 | 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 | 7903 | return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern()); |
| 7911 | 7904 | } |
| 7912 | 7905 | |
| 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 | 7906 | if (try dest_ty.onePossibleValue(pt)) |opv| { |
| 7918 | 7907 | if (block.wantSafety()) { |
| 7919 | 7908 | // The operand is runtime-known but the result is comptime-known. In |
| ... | ... | @@ -9940,13 +9929,6 @@ fn analyzeSwitchBlock( |
| 9940 | 9929 | operand_ty.containerLayout(zcu) != .@"packed"; |
| 9941 | 9930 | const err_set = operand_ty.zigTypeTag(zcu) == .error_set; |
| 9942 | 9931 | |
| 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 | 9932 | const cond_ref = switch (operand) { |
| 9951 | 9933 | .simple => |s| s.cond, |
| 9952 | 9934 | .loop => |l| l.init_cond, |
| ... | ... | @@ -19567,14 +19549,6 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19567 | 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 | 19552 | const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src); |
| 19579 | 19553 | if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { |
| 19580 | 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 | 33959 | // The `tagValueIndex` function call below relies on the type being the integer tag type. |
| 33986 | 33960 | // `getCoerced` assumes the value will fit the new type. |
| 33987 | 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 | 33963 | if (!int.intFitsInType(int_tag_ty, null, zcu)) return false; |
| 33989 | 33964 | const int_coerced = try pt.getCoerced(int, int_tag_ty); |
| 33990 | 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 | 1325 | const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index); |
| 1326 | 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 | 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 | &block, | |
| 1331 | block.src(.container_arg), | |
| 1332 | "expected integer tag type, found '{f}'", | |
| 1333 | .{int_tag_ty.fmt(pt)}, | |
| 1334 | ); | |
| 1330 | switch (int_tag_ty.zigTypeTag(zcu)) { | |
| 1331 | .int => if (empty_exhaustive) return sema.fail( | |
| 1332 | &block, | |
| 1333 | block.src(.container_arg), | |
| 1334 | "empty exhaustive enums must be backed by 'noreturn'", | |
| 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 | 1350 | break :ty int_tag_ty; |
| 1336 | 1351 | } else ty: { |
| 1352 | if (empty_exhaustive) break :ty .noreturn; | |
| 1337 | 1353 | // Infer the int tag type from the field count |
| 1338 | 1354 | const bits = Type.smallestUnsignedBits(enum_obj.field_names.len -| 1); |
| 1339 | 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 | 3058 | .one, .many, .c => .pointer, |
| 3059 | 3059 | }, |
| 3060 | 3060 | |
| 3061 | .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_mode) { | |
| 3062 | .explicit => null, | |
| 3063 | .auto => .{ .enum_inferred_int_tag = ty }, | |
| 3061 | .@"enum" => { | |
| 3062 | const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern()); | |
| 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 | }, |
| 3065 | 3071 | |
| 3066 | 3072 | .@"struct" => switch (ty.containerLayout(zcu)) { |
src/link/Dwarf.zig+1| ... | ... | @@ -5098,6 +5098,7 @@ fn DeclValEnum(comptime T: type) type { |
| 5098 | 5098 | if (min_value == null or min_value.? > value) min_value = value; |
| 5099 | 5099 | if (max_value == null or max_value.? < value) max_value = value; |
| 5100 | 5100 | } |
| 5101 | if (fields_len == 0) return enum {}; | |
| 5101 | 5102 | const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0); |
| 5102 | 5103 | var field_vals: [fields_len]TagInt = undefined; |
| 5103 | 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 | 1451 | comptime assert(@intFromEnum(x) == 0); |
| 1452 | 1452 | } |
| 1453 | 1453 | |
| 1454 | test "switch on empty enum" { | |
| 1455 | const E = enum {}; | |
| 1456 | var e: E = undefined; | |
| 1457 | _ = &e; | |
| 1458 | switch (e) {} | |
| 1459 | } | |
| 1460 | ||
| 1461 | test "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 | ||
| 1468 | test "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 | ||
| 1477 | 1454 | test "enum int tag type uses declaration inside the enum" { |
| 1478 | 1455 | const static = struct { |
| 1479 | 1456 | const E = enum(E.IntTag) { |
test/behavior/type.zig+1-1| ... | ... | @@ -270,7 +270,7 @@ test "Type.Union from empty regular enum" { |
| 270 | 270 | } |
| 271 | 271 | |
| 272 | 272 | test "Type.Union from empty Type.Enum" { |
| 273 | const E = @Enum(u0, .exhaustive, &.{}, &.{}); | |
| 273 | const E = @Enum(noreturn, .exhaustive, &.{}, &.{}); | |
| 274 | 274 | const U = @Union(.auto, E, &.{}, &.{}, &.{}); |
| 275 | 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 @@ |
| 1 | const E1 = enum(u32) {}; | |
| 2 | export fn entry1() void { | |
| 3 | const e: E1 = undefined; | |
| 4 | _ = e; | |
| 5 | } | |
| 6 | ||
| 7 | const E2 = enum(noreturn) { a, b, c }; | |
| 8 | export 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 | pub const E = enum(u31) { A, B, C }; | |
| 2 | pub const S = extern struct { | |
| 3 | e: E, | |
| 4 | }; | |
| 5 | export fn entry() void { | |
| 6 | const s: S = undefined; | |
| 7 | _ = s; | |
| 1 | export fn entry1() void { | |
| 2 | const E = enum(u31) { A, B, C }; | |
| 3 | _ = @sizeOf(extern struct { | |
| 4 | x: E, | |
| 5 | }); | |
| 6 | } | |
| 7 | export fn entry2() void { | |
| 8 | const E = enum(noreturn) {}; | |
| 9 | _ = @sizeOf(extern struct { | |
| 10 | x: E, | |
| 11 | }); | |
| 8 | 12 | } |
| 9 | 13 | |
| 10 | 14 | // error |
| 11 | 15 | // |
| 12 | // :3:8: error: extern structs cannot contain fields of type 'tmp.E' | |
| 13 | // :1: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 compatible | |
| 15 | // :1:15: note: enum declared here | |
| 16 | // :4:12: error: extern structs cannot contain fields of type 'tmp.entry1.E' | |
| 17 | // :2:15: note: enum tag type 'u31' is not extern compatible | |
| 18 | // :2:15: note: only integers with 0 or power of two bits are extern compatible | |
| 19 | // :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 | 1 | const EnumInferred = enum {}; |
| 2 | const EnumExplicit = enum(u8) {}; | |
| 2 | const EnumExplicit = enum(noreturn) {}; | |
| 3 | 3 | const EnumNonexhaustive = enum(u8) { _ }; |
| 4 | 4 | |
| 5 | 5 | const U0 = union {}; |
| 6 | 6 | const U1 = union(enum) {}; |
| 7 | const U2 = union(enum(u8)) {}; | |
| 7 | const U2 = union(enum(noreturn)) {}; | |
| 8 | 8 | const U3 = union(EnumInferred) {}; |
| 9 | 9 | const U4 = union(EnumExplicit) {}; |
| 10 | 10 | const U5 = union(EnumNonexhaustive) {}; |
test/cases/compile_errors/instantiate_empty_enum.zig created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | const E = enum {}; | |
| 2 | ||
| 3 | export fn entry1() void { | |
| 4 | const e: E = undefined; | |
| 5 | _ = e; | |
| 6 | } | |
| 7 | ||
| 8 | export fn entry2() void { | |
| 9 | const e: E = @enumFromInt(@as(u8, undefined)); | |
| 10 | _ = e; | |
| 11 | } | |
| 12 | ||
| 13 | export fn entry3() void { | |
| 14 | const e: E = .a; | |
| 15 | _ = e; | |
| 16 | } | |
| 17 | ||
| 18 | export 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 @@ |
| 1 | export 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 | 81 | x: *const u32, |
| 82 | 82 | }); |
| 83 | 83 | } |
| 84 | export fn entry16() void { | |
| 85 | const E = enum(noreturn) {}; | |
| 86 | _ = @sizeOf(packed struct { | |
| 87 | x: E, | |
| 88 | }); | |
| 89 | } | |
| 84 | 90 | |
| 85 | 91 | // error |
| 86 | 92 | // |
| ... | ... | @@ -114,3 +120,5 @@ export fn entry15() void { |
| 114 | 120 | // :81:12: error: packed structs cannot contain fields of type '*const u32' |
| 115 | 121 | // :81:12: note: pointers cannot be directly bitpacked |
| 116 | 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 | 10 | x: *const u32, |
| 11 | 11 | }); |
| 12 | 12 | } |
| 13 | export fn entry2() void { | |
| 14 | const E = enum(noreturn) {}; | |
| 15 | _ = @sizeOf(packed union { | |
| 16 | x: E, | |
| 17 | }); | |
| 18 | } | |
| 13 | 19 | |
| 14 | 20 | // error |
| 15 | 21 | // |
| ... | ... | @@ -19,3 +25,5 @@ export fn entry1() void { |
| 19 | 25 | // :10:12: error: packed unions cannot contain fields of type '*const u32' |
| 20 | 26 | // :10:12: note: pointers cannot be directly bitpacked |
| 21 | 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 | const Tag = @Enum(u0, .exhaustive, &.{}, &.{}); | |
| 1 | const Tag = @Enum(noreturn, .exhaustive, &.{}, &.{}); | |
| 2 | 2 | const Tagged = @Union(.auto, Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &@splat(.{})); |
| 3 | 3 | export fn entry() void { |
| 4 | 4 | const tagged: Tagged = undefined; |
test/cases/compile_errors/sizeof_alignof_empty_union.zig+2-2| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | const EnumInferred = enum {}; |
| 2 | const EnumExplicit = enum(u8) {}; | |
| 2 | const EnumExplicit = enum(noreturn) {}; | |
| 3 | 3 | const EnumNonexhaustive = enum(u8) { _ }; |
| 4 | 4 | |
| 5 | 5 | const U0 = union {}; |
| 6 | 6 | const U1 = union(enum) {}; |
| 7 | const U2 = union(enum(u8)) {}; | |
| 7 | const U2 = union(enum(noreturn)) {}; | |
| 8 | 8 | const U3 = union(EnumInferred) {}; |
| 9 | 9 | const U4 = union(EnumExplicit) {}; |
| 10 | 10 | const U5 = union(EnumNonexhaustive) {}; |