authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-08 14:11:09+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:10+00:00
log4f7344dec0bc61916f0c9af99bc5b5e5b7167da3
tree784154f34a6ec49d6245c6e6020db0afb2d237de
parentffc5242169d67840e0d1420b792696fc1b3d1722
signaturelock-open Commit is signed but in an unrecognized format.

tests: update for accepted language change

Unions with no fields are now "uninstantiable" types, which work like `noreturn` in that values of this type cannot exist. Enums with no fields are different because they are currently considered `extern` types, though https://github.com/ziglang/zig/issues/19855 will change this in the future.

7 files changed, 195 insertions(+), 67 deletions(-)

test/behavior.zig-1
......@@ -24,7 +24,6 @@ test {
2424 _ = @import("behavior/duplicated_test_names.zig");
2525 _ = @import("behavior/defer.zig");
2626 _ = @import("behavior/destructure.zig");
27 _ = @import("behavior/empty_union.zig");
2827 _ = @import("behavior/enum.zig");
2928 _ = @import("behavior/error.zig");
3029 _ = @import("behavior/eval.zig");
test/behavior/empty_union.zig deleted-66
......@@ -1,66 +0,0 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4
5test "switch on empty enum" {
6 const E = enum {};
7 var e: E = undefined;
8 _ = &e;
9 switch (e) {}
10}
11
12test "switch on empty enum with a specified tag type" {
13 const E = enum(u8) {};
14 var e: E = undefined;
15 _ = &e;
16 switch (e) {}
17}
18
19test "switch on empty auto numbered tagged union" {
20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21
22 const U = union(enum(u8)) {};
23 var u: U = undefined;
24 _ = &u;
25 switch (u) {}
26}
27
28test "switch on empty tagged union" {
29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
30
31 const E = enum {};
32 const U = union(E) {};
33 var u: U = undefined;
34 _ = &u;
35 switch (u) {}
36}
37
38test "empty union" {
39 const U = union {};
40 try expect(@sizeOf(U) == 0);
41 try expect(@alignOf(U) == 1);
42}
43
44test "empty extern union" {
45 const U = extern union {};
46 try expect(@sizeOf(U) == 0);
47 try expect(@alignOf(U) == 1);
48}
49
50test "empty union passed as argument" {
51 const U = union(enum) {
52 fn f(u: @This()) void {
53 switch (u) {}
54 }
55 };
56 U.f(@as(U, undefined));
57}
58
59test "empty enum passed as argument" {
60 const E = enum {
61 fn f(e: @This()) void {
62 switch (e) {}
63 }
64 };
65 E.f(@as(E, undefined));
66}
test/behavior/enum.zig+23
......@@ -1331,3 +1331,26 @@ test "comptime @enumFromInt with signed arithmetic" {
13311331 comptime assert(x == .bar);
13321332 comptime assert(@intFromEnum(x) == 0);
13331333}
1334
1335test "switch on empty enum" {
1336 const E = enum {};
1337 var e: E = undefined;
1338 _ = &e;
1339 switch (e) {}
1340}
1341
1342test "switch on empty enum with a specified tag type" {
1343 const E = enum(u8) {};
1344 var e: E = undefined;
1345 _ = &e;
1346 switch (e) {}
1347}
1348
1349test "empty enum passed as argument" {
1350 const E = enum {
1351 fn f(e: @This()) void {
1352 switch (e) {}
1353 }
1354 };
1355 E.f(@as(E, undefined));
1356}
test/cases/compile_errors/empty_extern_union.zig created+8
......@@ -0,0 +1,8 @@
1export fn foo() void {
2 const U = extern union {};
3 _ = @as(U, undefined);
4}
5
6// error
7//
8// :2:22: error: extern union has no fields
test/cases/compile_errors/empty_packed_union.zig created+8
......@@ -0,0 +1,8 @@
1export fn foo() void {
2 const U = packed union {};
3 _ = @as(U, undefined);
4}
5
6// error
7//
8// :2:22: error: packed union has no fields
test/cases/compile_errors/initialize_empty_union.zig created+81
......@@ -0,0 +1,81 @@
1const EnumInferred = enum {};
2const EnumExplicit = enum(u8) {};
3const EnumNonexhaustive = enum(u8) { _ };
4
5const U0 = union {};
6const U1 = union(enum) {};
7const U2 = union(enum(u8)) {};
8const U3 = union(EnumInferred) {};
9const U4 = union(EnumExplicit) {};
10const U5 = union(EnumNonexhaustive) {};
11
12export fn init0() void {
13 _ = @as(U0, undefined);
14}
15export fn init1() void {
16 _ = @as(U1, undefined);
17}
18export fn init2() void {
19 _ = @as(U2, undefined);
20}
21export fn init3() void {
22 _ = @as(U3, undefined);
23}
24export fn init4() void {
25 _ = @as(U4, undefined);
26}
27export fn init5() void {
28 _ = @as(U5, undefined);
29}
30
31export fn deref0(ptr: *const U0) void {
32 _ = ptr.*;
33}
34export fn deref1(ptr: *const U1) void {
35 _ = ptr.*;
36}
37export fn deref2(ptr: *const U2) void {
38 _ = ptr.*;
39}
40export fn deref3(ptr: *const U3) void {
41 _ = ptr.*;
42}
43export fn deref4(ptr: *const U4) void {
44 _ = ptr.*;
45}
46export fn deref5(ptr: *const U5) void {
47 _ = ptr.*;
48}
49
50// error
51//
52// :13:17: error: expected type 'initialize_empty_union.U0', found '@TypeOf(undefined)'
53// :13:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U0'
54// :5:12: note: union declared here
55// :16:17: error: expected type 'initialize_empty_union.U1', found '@TypeOf(undefined)'
56// :16:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U1'
57// :6:12: note: union declared here
58// :19:17: error: expected type 'initialize_empty_union.U2', found '@TypeOf(undefined)'
59// :19:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U2'
60// :7:12: note: union declared here
61// :22:17: error: expected type 'initialize_empty_union.U3', found '@TypeOf(undefined)'
62// :22:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U3'
63// :8:12: note: union declared here
64// :25:17: error: expected type 'initialize_empty_union.U4', found '@TypeOf(undefined)'
65// :25:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U4'
66// :9:12: note: union declared here
67// :28:17: error: expected type 'initialize_empty_union.U5', found '@TypeOf(undefined)'
68// :28:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U5'
69// :10:12: note: union declared here
70// :32:12: error: cannot load uninstantiable type 'initialize_empty_union.U0'
71// :5:12: note: union declared here
72// :35:12: error: cannot load uninstantiable type 'initialize_empty_union.U1'
73// :6:12: note: union declared here
74// :38:12: error: cannot load uninstantiable type 'initialize_empty_union.U2'
75// :7:12: note: union declared here
76// :41:12: error: cannot load uninstantiable type 'initialize_empty_union.U3'
77// :8:12: note: union declared here
78// :44:12: error: cannot load uninstantiable type 'initialize_empty_union.U4'
79// :9:12: note: union declared here
80// :47:12: error: cannot load uninstantiable type 'initialize_empty_union.U5'
81// :10:12: note: union declared here
test/cases/compile_errors/sizeof_alignof_empty_union.zig created+75
......@@ -0,0 +1,75 @@
1const EnumInferred = enum {};
2const EnumExplicit = enum(u8) {};
3const EnumNonexhaustive = enum(u8) { _ };
4
5const U0 = union {};
6const U1 = union(enum) {};
7const U2 = union(enum(u8)) {};
8const U3 = union(EnumInferred) {};
9const U4 = union(EnumExplicit) {};
10const U5 = union(EnumNonexhaustive) {};
11
12export fn size0() void {
13 _ = @sizeOf(U0);
14}
15export fn size1() void {
16 _ = @sizeOf(U1);
17}
18export fn size2() void {
19 _ = @sizeOf(U2);
20}
21export fn size3() void {
22 _ = @sizeOf(U3);
23}
24export fn size4() void {
25 _ = @sizeOf(U4);
26}
27export fn size5() void {
28 _ = @sizeOf(U5);
29}
30
31export fn align0() void {
32 _ = @alignOf(U0);
33}
34export fn align1() void {
35 _ = @alignOf(U1);
36}
37export fn align2() void {
38 _ = @alignOf(U2);
39}
40export fn align3() void {
41 _ = @alignOf(U3);
42}
43export fn align4() void {
44 _ = @alignOf(U4);
45}
46export fn align5() void {
47 _ = @alignOf(U5);
48}
49
50// error
51//
52// :13:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U0'
53// :5:12: note: union declared here
54// :16:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U1'
55// :6:12: note: union declared here
56// :19:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U2'
57// :7:12: note: union declared here
58// :22:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U3'
59// :8:12: note: union declared here
60// :25:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U4'
61// :9:12: note: union declared here
62// :28:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U5'
63// :10:12: note: union declared here
64// :32:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U0'
65// :5:12: note: union declared here
66// :35:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U1'
67// :6:12: note: union declared here
68// :38:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U2'
69// :7:12: note: union declared here
70// :41:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U3'
71// :8:12: note: union declared here
72// :44:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U4'
73// :9:12: note: union declared here
74// :47:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U5'
75// :10:12: note: union declared here