From 4f7344dec0bc61916f0c9af99bc5b5e5b7167da3 Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Sun, 8 Feb 2026 14:11:09 +0000 Subject: [PATCH] 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. --- test/behavior.zig | 1 - test/behavior/empty_union.zig | 66 --------------- test/behavior/enum.zig | 23 ++++++ .../compile_errors/empty_extern_union.zig | 8 ++ .../compile_errors/empty_packed_union.zig | 8 ++ .../compile_errors/initialize_empty_union.zig | 81 +++++++++++++++++++ .../sizeof_alignof_empty_union.zig | 75 +++++++++++++++++ 7 files changed, 195 insertions(+), 67 deletions(-) delete mode 100644 test/behavior/empty_union.zig create mode 100644 test/cases/compile_errors/empty_extern_union.zig create mode 100644 test/cases/compile_errors/empty_packed_union.zig create mode 100644 test/cases/compile_errors/initialize_empty_union.zig create mode 100644 test/cases/compile_errors/sizeof_alignof_empty_union.zig diff --git a/test/behavior.zig b/test/behavior.zig index e4153c91bb..c9c06e9342 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -24,7 +24,6 @@ test { _ = @import("behavior/duplicated_test_names.zig"); _ = @import("behavior/defer.zig"); _ = @import("behavior/destructure.zig"); - _ = @import("behavior/empty_union.zig"); _ = @import("behavior/enum.zig"); _ = @import("behavior/error.zig"); _ = @import("behavior/eval.zig"); diff --git a/test/behavior/empty_union.zig b/test/behavior/empty_union.zig deleted file mode 100644 index f05feacfaf..0000000000 --- a/test/behavior/empty_union.zig +++ /dev/null @@ -1,66 +0,0 @@ -const builtin = @import("builtin"); -const std = @import("std"); -const expect = std.testing.expect; - -test "switch on empty enum" { - const E = enum {}; - var e: E = undefined; - _ = &e; - switch (e) {} -} - -test "switch on empty enum with a specified tag type" { - const E = enum(u8) {}; - var e: E = undefined; - _ = &e; - switch (e) {} -} - -test "switch on empty auto numbered tagged union" { - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - - const U = union(enum(u8)) {}; - var u: U = undefined; - _ = &u; - switch (u) {} -} - -test "switch on empty tagged union" { - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - - const E = enum {}; - const U = union(E) {}; - var u: U = undefined; - _ = &u; - switch (u) {} -} - -test "empty union" { - const U = union {}; - try expect(@sizeOf(U) == 0); - try expect(@alignOf(U) == 1); -} - -test "empty extern union" { - const U = extern union {}; - try expect(@sizeOf(U) == 0); - try expect(@alignOf(U) == 1); -} - -test "empty union passed as argument" { - const U = union(enum) { - fn f(u: @This()) void { - switch (u) {} - } - }; - U.f(@as(U, undefined)); -} - -test "empty enum passed as argument" { - const E = enum { - fn f(e: @This()) void { - switch (e) {} - } - }; - E.f(@as(E, undefined)); -} diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index a222bd6051..4dd5ae08da 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -1331,3 +1331,26 @@ test "comptime @enumFromInt with signed arithmetic" { comptime assert(x == .bar); comptime assert(@intFromEnum(x) == 0); } + +test "switch on empty enum" { + const E = enum {}; + var e: E = undefined; + _ = &e; + switch (e) {} +} + +test "switch on empty enum with a specified tag type" { + const E = enum(u8) {}; + var e: E = undefined; + _ = &e; + switch (e) {} +} + +test "empty enum passed as argument" { + const E = enum { + fn f(e: @This()) void { + switch (e) {} + } + }; + E.f(@as(E, undefined)); +} diff --git a/test/cases/compile_errors/empty_extern_union.zig b/test/cases/compile_errors/empty_extern_union.zig new file mode 100644 index 0000000000..44d6269617 --- /dev/null +++ b/test/cases/compile_errors/empty_extern_union.zig @@ -0,0 +1,8 @@ +export fn foo() void { + const U = extern union {}; + _ = @as(U, undefined); +} + +// error +// +// :2:22: error: extern union has no fields diff --git a/test/cases/compile_errors/empty_packed_union.zig b/test/cases/compile_errors/empty_packed_union.zig new file mode 100644 index 0000000000..8720967097 --- /dev/null +++ b/test/cases/compile_errors/empty_packed_union.zig @@ -0,0 +1,8 @@ +export fn foo() void { + const U = packed union {}; + _ = @as(U, undefined); +} + +// error +// +// :2:22: error: packed union has no fields diff --git a/test/cases/compile_errors/initialize_empty_union.zig b/test/cases/compile_errors/initialize_empty_union.zig new file mode 100644 index 0000000000..c84633da26 --- /dev/null +++ b/test/cases/compile_errors/initialize_empty_union.zig @@ -0,0 +1,81 @@ +const EnumInferred = enum {}; +const EnumExplicit = enum(u8) {}; +const EnumNonexhaustive = enum(u8) { _ }; + +const U0 = union {}; +const U1 = union(enum) {}; +const U2 = union(enum(u8)) {}; +const U3 = union(EnumInferred) {}; +const U4 = union(EnumExplicit) {}; +const U5 = union(EnumNonexhaustive) {}; + +export fn init0() void { + _ = @as(U0, undefined); +} +export fn init1() void { + _ = @as(U1, undefined); +} +export fn init2() void { + _ = @as(U2, undefined); +} +export fn init3() void { + _ = @as(U3, undefined); +} +export fn init4() void { + _ = @as(U4, undefined); +} +export fn init5() void { + _ = @as(U5, undefined); +} + +export fn deref0(ptr: *const U0) void { + _ = ptr.*; +} +export fn deref1(ptr: *const U1) void { + _ = ptr.*; +} +export fn deref2(ptr: *const U2) void { + _ = ptr.*; +} +export fn deref3(ptr: *const U3) void { + _ = ptr.*; +} +export fn deref4(ptr: *const U4) void { + _ = ptr.*; +} +export fn deref5(ptr: *const U5) void { + _ = ptr.*; +} + +// error +// +// :13:17: error: expected type 'initialize_empty_union.U0', found '@TypeOf(undefined)' +// :13:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U0' +// :5:12: note: union declared here +// :16:17: error: expected type 'initialize_empty_union.U1', found '@TypeOf(undefined)' +// :16:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U1' +// :6:12: note: union declared here +// :19:17: error: expected type 'initialize_empty_union.U2', found '@TypeOf(undefined)' +// :19:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U2' +// :7:12: note: union declared here +// :22:17: error: expected type 'initialize_empty_union.U3', found '@TypeOf(undefined)' +// :22:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U3' +// :8:12: note: union declared here +// :25:17: error: expected type 'initialize_empty_union.U4', found '@TypeOf(undefined)' +// :25:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U4' +// :9:12: note: union declared here +// :28:17: error: expected type 'initialize_empty_union.U5', found '@TypeOf(undefined)' +// :28:17: note: cannot coerce to uninstantiable type 'initialize_empty_union.U5' +// :10:12: note: union declared here +// :32:12: error: cannot load uninstantiable type 'initialize_empty_union.U0' +// :5:12: note: union declared here +// :35:12: error: cannot load uninstantiable type 'initialize_empty_union.U1' +// :6:12: note: union declared here +// :38:12: error: cannot load uninstantiable type 'initialize_empty_union.U2' +// :7:12: note: union declared here +// :41:12: error: cannot load uninstantiable type 'initialize_empty_union.U3' +// :8:12: note: union declared here +// :44:12: error: cannot load uninstantiable type 'initialize_empty_union.U4' +// :9:12: note: union declared here +// :47:12: error: cannot load uninstantiable type 'initialize_empty_union.U5' +// :10:12: note: union declared here diff --git a/test/cases/compile_errors/sizeof_alignof_empty_union.zig b/test/cases/compile_errors/sizeof_alignof_empty_union.zig new file mode 100644 index 0000000000..920b3b5af8 --- /dev/null +++ b/test/cases/compile_errors/sizeof_alignof_empty_union.zig @@ -0,0 +1,75 @@ +const EnumInferred = enum {}; +const EnumExplicit = enum(u8) {}; +const EnumNonexhaustive = enum(u8) { _ }; + +const U0 = union {}; +const U1 = union(enum) {}; +const U2 = union(enum(u8)) {}; +const U3 = union(EnumInferred) {}; +const U4 = union(EnumExplicit) {}; +const U5 = union(EnumNonexhaustive) {}; + +export fn size0() void { + _ = @sizeOf(U0); +} +export fn size1() void { + _ = @sizeOf(U1); +} +export fn size2() void { + _ = @sizeOf(U2); +} +export fn size3() void { + _ = @sizeOf(U3); +} +export fn size4() void { + _ = @sizeOf(U4); +} +export fn size5() void { + _ = @sizeOf(U5); +} + +export fn align0() void { + _ = @alignOf(U0); +} +export fn align1() void { + _ = @alignOf(U1); +} +export fn align2() void { + _ = @alignOf(U2); +} +export fn align3() void { + _ = @alignOf(U3); +} +export fn align4() void { + _ = @alignOf(U4); +} +export fn align5() void { + _ = @alignOf(U5); +} + +// error +// +// :13:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U0' +// :5:12: note: union declared here +// :16:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U1' +// :6:12: note: union declared here +// :19:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U2' +// :7:12: note: union declared here +// :22:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U3' +// :8:12: note: union declared here +// :25:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U4' +// :9:12: note: union declared here +// :28:17: error: no size available for uninstantiable type 'sizeof_alignof_empty_union.U5' +// :10:12: note: union declared here +// :32:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U0' +// :5:12: note: union declared here +// :35:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U1' +// :6:12: note: union declared here +// :38:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U2' +// :7:12: note: union declared here +// :41:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U3' +// :8:12: note: union declared here +// :44:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U4' +// :9:12: note: union declared here +// :47:18: error: no align available for uninstantiable type 'sizeof_alignof_empty_union.U5' +// :10:12: note: union declared here