From b9a63433b71e8b07691da158a136d17e1f04c49b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 5 Sep 2025 19:33:30 -0700 Subject: [PATCH] behavior tests: update for new requirement packed union fields must all have matching bit sizes --- test/behavior/cast_int.zig | 22 +++-- test/behavior/export_keyword.zig | 7 +- test/behavior/field_parent_ptr.zig | 18 ++-- test/behavior/packed-struct.zig | 8 +- test/behavior/packed-union.zig | 17 ++-- test/behavior/union.zig | 136 ++++++++++++++--------------- 6 files changed, 116 insertions(+), 92 deletions(-) diff --git a/test/behavior/cast_int.zig b/test/behavior/cast_int.zig index 0c4d01f501..8a1fcf79b2 100644 --- a/test/behavior/cast_int.zig +++ b/test/behavior/cast_int.zig @@ -225,20 +225,26 @@ test "load non byte-sized value in union" { // using ptrCast not to depend on unitialised memory state var union0: packed union { - p: Piece, + p: packed struct(u8) { + a: Piece, + b: u4, + }, int: u8, } = .{ .int = 0 }; union0.int = 0b11111011; - try expect(union0.p.type == .PAWN); - try expect(union0.p.color == .BLACK); + try expect(union0.p.a.type == .PAWN); + try expect(union0.p.a.color == .BLACK); var union1: union { - p: Piece, + p: packed struct(u8) { + a: Piece, + b: u4, + }, int: u8, - } = .{ .p = .{ .color = .WHITE, .type = .KING } }; - @as(*u8, @ptrCast(&union1.p)).* = 0b11111011; - try expect(union1.p.type == .PAWN); - try expect(union1.p.color == .BLACK); + } = .{ .p = .{ .a = .{ .color = .WHITE, .type = .KING }, .b = 0 } }; + @as(*u8, @ptrCast(&union1.p.a)).* = 0b11111011; + try expect(union1.p.a.type == .PAWN); + try expect(union1.p.a.color == .BLACK); var pieces: [3]Piece = undefined; @as(*u8, @ptrCast(&pieces[1])).* = 0b11111011; diff --git a/test/behavior/export_keyword.zig b/test/behavior/export_keyword.zig index af2065067e..f6b5126eb2 100644 --- a/test/behavior/export_keyword.zig +++ b/test/behavior/export_keyword.zig @@ -19,7 +19,10 @@ const PackedStruct = packed struct { b: u8, }; const PackedUnion = packed union { - a: u8, + a: packed struct(u32) { + a: u8, + b: u24 = 0, + }, b: u32, }; @@ -29,7 +32,7 @@ test "packed struct, enum, union parameters in extern function" { testPackedStuff(&(PackedStruct{ .a = 1, .b = 2, - }), &(PackedUnion{ .a = 1 })); + }), &(PackedUnion{ .a = .{ .a = 1 } })); } export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void { diff --git a/test/behavior/field_parent_ptr.zig b/test/behavior/field_parent_ptr.zig index 65050e3df0..0bfec91d84 100644 --- a/test/behavior/field_parent_ptr.zig +++ b/test/behavior/field_parent_ptr.zig @@ -1758,27 +1758,33 @@ test "@fieldParentPtr packed union" { if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // TODO const C = packed union { - a: bool, + a: packed struct(u32) { + a: bool, + b: u31 = 0, + }, b: f32, - c: packed struct { x: u8 }, + c: packed struct(u32) { + x: u8, + b: u24 = 0, + }, d: i32, }; { - const c: C = .{ .a = false }; + const c: C = .{ .a = .{ .a = false } }; const pcf = &c.a; const pc: *const C = @alignCast(@fieldParentPtr("a", pcf)); try expect(pc == &c); } { - const c: C = .{ .a = false }; + const c: C = .{ .a = .{ .a = false } }; const pcf = &c.a; var pc: *const C = undefined; pc = @alignCast(@fieldParentPtr("a", pcf)); try expect(pc == &c); } { - const c: C = .{ .a = false }; + const c: C = .{ .a = .{ .a = false } }; var pcf: @TypeOf(&c.a) = undefined; pcf = &c.a; var pc: *const C = undefined; @@ -1787,7 +1793,7 @@ test "@fieldParentPtr packed union" { } { var c: C = undefined; - c = .{ .a = false }; + c = .{ .a = .{ .a = false } }; var pcf: @TypeOf(&c.a) = undefined; pcf = &c.a; var pc: *C = undefined; diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index b2b4f89eb8..8352c493a2 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -1223,7 +1223,13 @@ test "load flag from packed struct in union" { test "bitcasting a packed struct at comptime and using the result" { comptime { const Struct = packed struct { - x: packed union { a: u63, b: i32 }, + x: packed union { + a: u63, + b: packed struct(u63) { + a: i32, + b: u31 = 0, + }, + }, y: u1, pub fn bitcast(fd: u64) @This() { diff --git a/test/behavior/packed-union.zig b/test/behavior/packed-union.zig index ad31e590ba..bbb2f612b6 100644 --- a/test/behavior/packed-union.zig +++ b/test/behavior/packed-union.zig @@ -59,14 +59,17 @@ test "flags in packed union at offset" { fn testFlagsInPackedUnionAtOffset() !void { const FlagBits = packed union { - base_flags: packed union { - flags: packed struct(u4) { - enable_1: bool = true, - enable_2: bool = false, - enable_3: bool = false, - enable_4: bool = false, + base_flags: packed struct(u12) { + a: packed union { + flags: packed struct(u4) { + enable_1: bool = true, + enable_2: bool = false, + enable_3: bool = false, + enable_4: bool = false, + }, + bits: u4, }, - bits: u4, + pad: u8 = 0, }, adv_flags: packed struct(u12) { pad: u8 = 0, diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 04d07f91ae..1807cf14cf 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -223,7 +223,7 @@ test "packed union generates correctly aligned type" { const U = packed union { f1: *const fn () error{TestUnexpectedResult}!void, - f2: u32, + f2: usize, }; var foo = [_]U{ U{ .f1 = doTest }, @@ -356,10 +356,10 @@ test "simple union(enum(u32))" { const PackedPtrOrInt = packed union { ptr: *u8, - int: u64, + int: usize, }; test "packed union size" { - comptime assert(@sizeOf(PackedPtrOrInt) == 8); + comptime assert(@sizeOf(PackedPtrOrInt) == @sizeOf(usize)); } const ZeroBits = union { @@ -1337,7 +1337,7 @@ test "packed union in packed struct" { const S = packed struct { nested: packed union { - val: u16, + val: u32, foo: u32, }, bar: u16, @@ -1415,25 +1415,6 @@ test "union reassignment can use previous value" { try expect(a.b == 32); } -test "packed union with zero-bit field" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - - const S = packed struct { - nested: packed union { - zero: void, - sized: u32, - }, - bar: u32, - - fn doTest(self: @This()) !void { - try expect(self.bar == 42); - } - }; - try S.doTest(.{ .nested = .{ .zero = {} }, .bar = 42 }); -} - test "reinterpreting enum value inside packed union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -1632,15 +1613,15 @@ test "memset packed union" { const U = packed union { a: u32, - b: u8, + b: u32, }; const S = struct { fn doTheTest() !void { var u: U = undefined; - @memset(std.mem.asBytes(&u), 42); + @memset(@as([]u8, @ptrCast(&u)), 42); try expectEqual(@as(u32, 0x2a2a2a2a), u.a); - try expectEqual(@as(u8, 0x2a), u.b); + try expectEqual(@as(u32, 0x2a2a2a2a), u.b); } }; @@ -1732,10 +1713,19 @@ test "reinterpret packed union" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const U = packed union { - foo: u8, - bar: u29, + foo: packed struct(u64) { + a: u8, + b: u56, + }, + bar: packed struct(u64) { + a: u29, + b: u35, + }, baz: u64, - qux: u12, + qux: packed struct(u64) { + a: u12, + b: u52, + }, }; const S = struct { @@ -1745,16 +1735,16 @@ test "reinterpret packed union" { var u: U = undefined; @memset(std.mem.asBytes(&u), 0); u.baz = 0xbbbbbbbb; - u.qux = 0xe2a; + u.qux.a = 0xe2a; break :blk u; }; - try expectEqual(@as(u8, 0x2a), u.foo); - try expectEqual(@as(u12, 0xe2a), u.qux); + try expectEqual(@as(u8, 0x2a), u.foo.a); + try expectEqual(@as(u12, 0xe2a), u.qux.a); // https://github.com/ziglang/zig/issues/17360 if (@inComptime()) { - try expectEqual(@as(u29, 0x1bbbbe2a), u.bar); + try expectEqual(@as(u29, 0x1bbbbe2a), u.bar.a); try expectEqual(@as(u64, 0xbbbbbe2a), u.baz); } } @@ -1762,31 +1752,31 @@ test "reinterpret packed union" { { // Union initialization var u: U = .{ .baz = 0 }; // ensure all bits are defined - u.qux = 0xe2a; - try expectEqual(@as(u8, 0x2a), u.foo); - try expectEqual(@as(u12, 0xe2a), u.qux); - try expectEqual(@as(u29, 0xe2a), u.bar & 0xfff); + u.qux.a = 0xe2a; + try expectEqual(@as(u8, 0x2a), u.foo.a); + try expectEqual(@as(u12, 0xe2a), u.qux.a); + try expectEqual(@as(u29, 0xe2a), u.bar.a & 0xfff); try expectEqual(@as(u64, 0xe2a), u.baz & 0xfff); // Writing to a larger field u.baz = 0xbbbbbbbb; - try expectEqual(@as(u8, 0xbb), u.foo); - try expectEqual(@as(u12, 0xbbb), u.qux); - try expectEqual(@as(u29, 0x1bbbbbbb), u.bar); + try expectEqual(@as(u8, 0xbb), u.foo.a); + try expectEqual(@as(u12, 0xbbb), u.qux.a); + try expectEqual(@as(u29, 0x1bbbbbbb), u.bar.a); try expectEqual(@as(u64, 0xbbbbbbbb), u.baz); // Writing to the same field u.baz = 0xcccccccc; - try expectEqual(@as(u8, 0xcc), u.foo); - try expectEqual(@as(u12, 0xccc), u.qux); - try expectEqual(@as(u29, 0x0ccccccc), u.bar); + try expectEqual(@as(u8, 0xcc), u.foo.a); + try expectEqual(@as(u12, 0xccc), u.qux.a); + try expectEqual(@as(u29, 0x0ccccccc), u.bar.a); try expectEqual(@as(u64, 0xcccccccc), u.baz); // Writing to a smaller field - u.foo = 0xdd; - try expectEqual(@as(u8, 0xdd), u.foo); - try expectEqual(@as(u12, 0xcdd), u.qux); - try expectEqual(@as(u29, 0x0cccccdd), u.bar); + u.foo.a = 0xdd; + try expectEqual(@as(u8, 0xdd), u.foo.a); + try expectEqual(@as(u12, 0xcdd), u.qux.a); + try expectEqual(@as(u29, 0x0cccccdd), u.bar.a); try expectEqual(@as(u64, 0xccccccdd), u.baz); } } @@ -1807,7 +1797,10 @@ test "reinterpret packed union inside packed struct" { const U = packed union { a: u7, - b: u1, + b: packed struct(u7) { + a: u1, + b: u6, + }, }; const V = packed struct { @@ -1818,18 +1811,18 @@ test "reinterpret packed union inside packed struct" { const S = struct { fn doTheTest() !void { var v: V = undefined; - @memset(std.mem.asBytes(&v), 0x55); - try expectEqual(@as(u7, 0x55), v.lo.a); - try expectEqual(@as(u1, 1), v.lo.b); - try expectEqual(@as(u7, 0x2a), v.hi.a); - try expectEqual(@as(u1, 0), v.hi.b); + @memset(@as([]u8, @ptrCast(&v)), 0x55); + try expect(@as(u7, 0x55) == v.lo.a); + try expect(@as(u1, 1) == v.lo.b.a); + try expect(@as(u7, 0x2a) == v.hi.a); + try expect(@as(u1, 0) == v.hi.b.a); - v.lo.b = 0; - try expectEqual(@as(u7, 0x54), v.lo.a); - try expectEqual(@as(u1, 0), v.lo.b); - v.hi.b = 1; - try expectEqual(@as(u7, 0x2b), v.hi.a); - try expectEqual(@as(u1, 1), v.hi.b); + v.lo.b.a = 0; + try expect(@as(u7, 0x54) == v.lo.a); + try expect(@as(u1, 0) == v.lo.b.a); + v.hi.b.a = 1; + try expect(@as(u7, 0x2b) == v.hi.a); + try expect(@as(u1, 1) == v.hi.b.a); } }; @@ -1869,8 +1862,9 @@ test "inner struct initializer uses packed union layout" { a: packed struct { x: u32 = @alignOf(U) + 1, }, - b: packed struct { + b: packed struct(u32) { y: u16 = @sizeOf(U) + 2, + padding: u16 = 0, }, }; }; @@ -1898,7 +1892,7 @@ test "extern union initialized via reintepreted struct field initializer" { }; const S = extern struct { - u: U = std.mem.bytesAsValue(U, &bytes).*, + u: U = @as(*align(1) const U, @ptrCast(&bytes)).*, }; const s: S = .{}; @@ -1913,17 +1907,20 @@ test "packed union initialized via reintepreted struct field initializer" { const U = packed union { a: u32, - b: u8, + b: packed struct(u32) { + a: u8, + b: u24, + }, }; const S = packed struct { - u: U = std.mem.bytesAsValue(U, &bytes).*, + u: U = @as(*align(1) const U, @ptrCast(&bytes)).*, }; var s: S = .{}; _ = &s; try expect(s.u.a == littleToNativeEndian(u32, 0xddccbbaa)); - try expect(s.u.b == if (endian == .little) 0xaa else 0xdd); + try expect(s.u.b.a == if (endian == .little) 0xaa else 0xdd); } test "store of comptime reinterpreted memory to extern union" { @@ -1938,7 +1935,7 @@ test "store of comptime reinterpreted memory to extern union" { const reinterpreted = comptime b: { var u: U = undefined; - u = std.mem.bytesAsValue(U, &bytes).*; + u = @as(*align(1) const U, @ptrCast(&bytes)).*; break :b u; }; @@ -1955,19 +1952,22 @@ test "store of comptime reinterpreted memory to packed union" { const U = packed union { a: u32, - b: u8, + b: packed struct(u32) { + a: u8, + b: u24, + }, }; const reinterpreted = comptime b: { var u: U = undefined; - u = std.mem.bytesAsValue(U, &bytes).*; + u = @as(*align(1) const U, @ptrCast(&bytes)).*; break :b u; }; var u: U = reinterpreted; _ = &u; try expect(u.a == littleToNativeEndian(u32, 0xddccbbaa)); - try expect(u.b == if (endian == .little) 0xaa else 0xdd); + try expect(u.b.a == if (endian == .little) 0xaa else 0xdd); } test "union field is a pointer to an aligned version of itself" {