authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-08 14:40:18+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:10+00:00
logf9183edf08214d3ff014cfe26a5f218385ef5ccc
tree1ab0d86f271aea82294e7a69cc16610232567d59
parent031d109310fe1f7e68314069ddf5d0d1dd342098
signaturelock-open Commit is signed but in an unrecognized format.

tests: update for accepted language change

`packed struct`s and `packed union`s can no longer contain pointer fields. There are a few reasons for this, but in particular, binary formats do not typically support the relocation types we would need to lower such values into static memory. See the proposal at https://github.com/ziglang/zig/issues/24657 for details.

7 files changed, 33 insertions(+), 182 deletions(-)

test/behavior/bitcast.zig-29
......@@ -511,35 +511,6 @@ test "@bitCast of packed struct of bools all false" {
511511 try expect(@as(u8, @as(u4, @bitCast(p))) == 0);
512512}
513513
514test "@bitCast of packed struct containing pointer" {
515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
516 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
517 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
518 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
519 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://discourse.llvm.org/t/rfc-remove-most-constant-expressions/63179
520
521 const S = struct {
522 const A = packed struct {
523 ptr: *const u32,
524 };
525
526 const B = packed struct {
527 ptr: *const i32,
528 };
529
530 fn doTheTest() !void {
531 const x: u32 = 123;
532 var a: A = undefined;
533 a = .{ .ptr = &x };
534 const b: B = @bitCast(a);
535 try expect(b.ptr.* == 123);
536 }
537 };
538
539 try S.doTheTest();
540 try comptime S.doTheTest();
541}
542
543514test "@bitCast of extern struct containing pointer" {
544515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
545516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/packed-struct.zig-98
......@@ -438,27 +438,6 @@ test "nested packed struct field pointers" {
438438 try expectEqual(6, ptr_p1_b.*);
439439}
440440
441test "load pointer from packed struct" {
442 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
443 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
444 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
445 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
446 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
447
448 const A = struct {
449 index: u16,
450 };
451 const B = packed struct {
452 x: *A,
453 y: u32,
454 };
455 var a: A = .{ .index = 123 };
456 const b_list: []const B = &.{.{ .x = &a, .y = 99 }};
457 for (b_list) |b| {
458 try expect(b.x.index == 123);
459 }
460}
461
462441test "@intFromPtr on a packed struct field" {
463442 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
464443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -601,19 +580,6 @@ test "packed struct fields modification" {
601580 try expect(@as(u16, @bitCast(Small.p)) == 0x1313);
602581}
603582
604test "optional pointer in packed struct" {
605 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
606 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
607 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
608 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
609 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
610
611 const T = packed struct { ptr: ?*const u8 };
612 var n: u8 = 0;
613 const x = T{ .ptr = &n };
614 try expect(x.ptr.? == &n);
615}
616
617583test "nested packed struct field access test" {
618584 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
619585 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits
......@@ -1042,48 +1008,6 @@ test "packed struct acts as a namespace" {
10421008 try expect(foo == .fizz);
10431009}
10441010
1045test "pointer loaded correctly from packed struct" {
1046 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1047 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1048 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1049 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1050 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1051
1052 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
1053
1054 const RAM = struct {
1055 data: [0xFFFF + 1]u8,
1056 fn new() !@This() {
1057 return .{ .data = [_]u8{0} ** 0x10000 };
1058 }
1059 fn get(self: *@This(), addr: u16) u8 {
1060 return self.data[addr];
1061 }
1062 };
1063
1064 const CPU = packed struct {
1065 interrupts: bool,
1066 ram: *RAM,
1067 fn new(ram: *RAM) !@This() {
1068 return .{
1069 .ram = ram,
1070 .interrupts = false,
1071 };
1072 }
1073 fn tick(self: *@This()) !void {
1074 const queued_interrupts = self.ram.get(0xFFFF) & self.ram.get(0xFF0F);
1075 if (self.interrupts and queued_interrupts != 0) {
1076 self.interrupts = false;
1077 }
1078 }
1079 };
1080
1081 var ram = try RAM.new();
1082 var cpu = try CPU.new(&ram);
1083 try cpu.tick();
1084 try std.testing.expect(cpu.interrupts == false);
1085}
1086
10871011test "assignment to non-byte-aligned field in packed struct" {
10881012 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10891013 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -1227,13 +1151,6 @@ test "2-byte packed struct argument in C calling convention" {
12271151 }
12281152}
12291153
1230test "packed struct contains optional pointer" {
1231 const foo: packed struct {
1232 a: ?*@This() = null,
1233 } = .{};
1234 try expect(foo.a == null);
1235}
1236
12371154test "packed struct equality" {
12381155 const Foo = packed struct {
12391156 a: u4,
......@@ -1297,21 +1214,6 @@ test "assign packed struct initialized with RLS to packed struct literal field"
12971214 try expect(outer.x == x);
12981215}
12991216
1300test "byte-aligned packed relocation" {
1301 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1302 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
1303 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1304 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1305 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1306
1307 const S = struct {
1308 var global: u8 align(2) = 0;
1309 var packed_value: packed struct { x: u8, y: *align(2) u8 } = .{ .x = 111, .y = &global };
1310 };
1311 try expect(S.packed_value.x == 111);
1312 try expect(S.packed_value.y == &S.global);
1313}
1314
13151217test "packed struct store of comparison result" {
13161218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13171219 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/packed-union.zig-12
......@@ -177,15 +177,3 @@ test "assigning to non-active field at comptime" {
177177 test_bits.bits = .{};
178178 }
179179}
180
181test "comptime packed union of pointers" {
182 const U = packed union {
183 a: *const u32,
184 b: *const [1]u32,
185 };
186
187 const x: u32 = 123;
188 const u: U = .{ .a = &x };
189
190 comptime assert(u.b[0] == 123);
191}
test/behavior/union.zig+5-25
......@@ -217,26 +217,6 @@ test "union with specified enum tag" {
217217 try comptime doTest();
218218}
219219
220test "packed union generates correctly aligned type" {
221 // This test will be removed after the following accepted proposal is implemented:
222 // https://github.com/ziglang/zig/issues/24657
223 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
224 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
225 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
226 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
227 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
228
229 const U = packed union {
230 f1: *const fn () error{TestUnexpectedResult}!void,
231 f2: usize,
232 };
233 var foo = [_]U{
234 U{ .f1 = doTest },
235 U{ .f2 = 0 },
236 };
237 try foo[0].f1();
238}
239
240220fn doTest() error{TestUnexpectedResult}!void {
241221 try expect((try bar(Payload{ .A = 1234 })) == -10);
242222}
......@@ -359,12 +339,12 @@ test "simple union(enum(u32))" {
359339 try expect(@intFromEnum(@as(Tag(MultipleChoice), x)) == 60);
360340}
361341
362const PackedPtrOrInt = packed union {
363 ptr: *u8,
364 int: usize,
365};
366342test "packed union size" {
367 comptime assert(@sizeOf(PackedPtrOrInt) == @sizeOf(usize));
343 const U = packed union {
344 signed: isize,
345 unsigned: usize,
346 };
347 comptime assert(@sizeOf(U) == @sizeOf(usize));
368348}
369349
370350const ZeroBits = union {
test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig+8
......@@ -76,6 +76,11 @@ export fn entry14() void {
7676 x: E,
7777 });
7878}
79export fn entry15() void {
80 _ = @sizeOf(packed struct {
81 x: *const u32,
82 });
83}
7984
8085// error
8186//
......@@ -103,3 +108,6 @@ export fn entry14() void {
103108// :70:12: note: types are not available at runtime
104109// :76:12: error: packed structs cannot contain fields of type 'tmp.entry14.E'
105110// :74:15: note: enum declared here
111// :81:12: error: packed structs cannot contain fields of type '*const u32'
112// :81:12: note: pointers cannot be directly bitpacked
113// :81:12: note: consider using 'usize' and '@intFromPtr'
test/cases/compile_errors/packed_union_with_automatic_layout_field.zig deleted-18
......@@ -1,18 +0,0 @@
1const Foo = struct {
2 a: u32,
3 b: f32,
4};
5const Payload = packed union {
6 A: Foo,
7 B: bool,
8};
9export fn entry() void {
10 const a: Payload = .{ .B = true };
11 _ = a;
12}
13
14// error
15//
16// :6:8: error: packed unions cannot contain fields of type 'tmp.Foo'
17// :6:8: note: only packed structs layout are allowed in packed types
18// :1:13: note: struct declared here
test/cases/compile_errors/packed_union_with_fields_of_not_allowed_types.zig created+20
......@@ -0,0 +1,20 @@
1export fn entry0() void {
2 _ = @sizeOf(packed union {
3 foo: struct { a: u32 },
4 bar: bool,
5 });
6}
7export fn entry1() void {
8 _ = @sizeOf(packed union {
9 x: *const u32,
10 });
11}
12
13// error
14//
15// :3:14: error: packed unions cannot contain fields of type 'packed_union_with_fields_of_not_allowed_types.entry0__union_180__struct_182'
16// :3:14: note: non-packed structs do not have a bit-packed representation
17// :3:14: note: struct declared here
18// :9:12: error: packed unions cannot contain fields of type '*const u32'
19// :9:12: note: pointers cannot be directly bitpacked
20// :9:12: note: consider using 'usize' and '@intFromPtr'