Commit b9a63433b7

Andrew Kelley <andrew@ziglang.org>
2025-09-06 04:33:30
behavior tests: update for new requirement
packed union fields must all have matching bit sizes
1 parent 52c6d7a
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;
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 {
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;
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() {
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,
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);
-
-            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);
+            @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.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" {