master
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;
6
7test "flags in packed structs" {
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9
10 const Flags1 = packed struct {
11 // first 8 bits
12 b0_0: u1,
13 b0_1: u1,
14 b0_2: u1,
15 b0_3: u1,
16 b0_4: u1,
17 b0_5: u1,
18 b0_6: u1,
19 b0_7: u1,
20
21 // 7 more bits
22 b1_0: u1,
23 b1_1: u1,
24 b1_2: u1,
25 b1_3: u1,
26 b1_4: u1,
27 b1_5: u1,
28 b1_6: u1,
29
30 // some padding to fill to 24 bits
31 _: u9,
32 };
33
34 try expectEqual(@sizeOf(u24), @sizeOf(Flags1));
35 try expectEqual(24, @bitSizeOf(Flags1));
36
37 const Flags2 = packed struct {
38 // byte 0
39 b0_0: u1,
40 b0_1: u1,
41 b0_2: u1,
42 b0_3: u1,
43 b0_4: u1,
44 b0_5: u1,
45 b0_6: u1,
46 b0_7: u1,
47
48 // partial byte 1 (but not 8 bits)
49 b1_0: u1,
50 b1_1: u1,
51 b1_2: u1,
52 b1_3: u1,
53 b1_4: u1,
54 b1_5: u1,
55 b1_6: u1,
56
57 // some padding that should yield @sizeOf(Flags2) == 4
58 _: u10,
59 };
60
61 try expectEqual(@sizeOf(u25), @sizeOf(Flags2));
62 try expectEqual(25, @bitSizeOf(Flags2));
63
64 const Flags3 = packed struct {
65 // byte 0
66 b0_0: u1,
67 b0_1: u1,
68 b0_2: u1,
69 b0_3: u1,
70 b0_4: u1,
71 b0_5: u1,
72 b0_6: u1,
73 b0_7: u1,
74
75 // byte 1
76 b1_0: u1,
77 b1_1: u1,
78 b1_2: u1,
79 b1_3: u1,
80 b1_4: u1,
81 b1_5: u1,
82 b1_6: u1,
83 b1_7: u1,
84
85 // some padding that should yield @sizeOf(Flags2) == 4
86 _: u16, // it works, if the padding is 8-based
87 };
88
89 try expectEqual(@sizeOf(u32), @sizeOf(Flags3));
90 try expectEqual(32, @bitSizeOf(Flags3));
91}
92
93test "consistent size of packed structs" {
94 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
95
96 const TxData1 = packed struct { data: u8, _23: u23, full: bool = false };
97 const TxData2 = packed struct { data: u9, _22: u22, full: bool = false };
98
99 const register_size_bits = 32;
100 const register_size_bytes = @sizeOf(u32);
101
102 try expectEqual(register_size_bits, @bitSizeOf(TxData1));
103 try expectEqual(register_size_bytes, @sizeOf(TxData1));
104
105 try expectEqual(register_size_bits, @bitSizeOf(TxData2));
106 try expectEqual(register_size_bytes, @sizeOf(TxData2));
107
108 const TxData4 = packed struct { a: u32, b: u24 };
109 const TxData6 = packed struct { a: u24, b: u32 };
110
111 const expectedBitSize = 56;
112 const expectedByteSize = @sizeOf(u56);
113
114 try expectEqual(expectedBitSize, @bitSizeOf(TxData4));
115 try expectEqual(expectedByteSize, @sizeOf(TxData4));
116
117 try expectEqual(expectedBitSize, @bitSizeOf(TxData6));
118 try expectEqual(expectedByteSize, @sizeOf(TxData6));
119}
120
121test "correct sizeOf and offsets in packed structs" {
122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
124
125 const PStruct = packed struct {
126 bool_a: bool,
127 bool_b: bool,
128 bool_c: bool,
129 bool_d: bool,
130 bool_e: bool,
131 bool_f: bool,
132 u1_a: u1,
133 bool_g: bool,
134 u1_b: u1,
135 u3_a: u3,
136 u10_a: u10,
137 u10_b: u10,
138 };
139 try expectEqual(0, @offsetOf(PStruct, "bool_a"));
140 try expectEqual(0, @bitOffsetOf(PStruct, "bool_a"));
141 try expectEqual(0, @offsetOf(PStruct, "bool_b"));
142 try expectEqual(1, @bitOffsetOf(PStruct, "bool_b"));
143 try expectEqual(0, @offsetOf(PStruct, "bool_c"));
144 try expectEqual(2, @bitOffsetOf(PStruct, "bool_c"));
145 try expectEqual(0, @offsetOf(PStruct, "bool_d"));
146 try expectEqual(3, @bitOffsetOf(PStruct, "bool_d"));
147 try expectEqual(0, @offsetOf(PStruct, "bool_e"));
148 try expectEqual(4, @bitOffsetOf(PStruct, "bool_e"));
149 try expectEqual(0, @offsetOf(PStruct, "bool_f"));
150 try expectEqual(5, @bitOffsetOf(PStruct, "bool_f"));
151 try expectEqual(0, @offsetOf(PStruct, "u1_a"));
152 try expectEqual(6, @bitOffsetOf(PStruct, "u1_a"));
153 try expectEqual(0, @offsetOf(PStruct, "bool_g"));
154 try expectEqual(7, @bitOffsetOf(PStruct, "bool_g"));
155 try expectEqual(1, @offsetOf(PStruct, "u1_b"));
156 try expectEqual(8, @bitOffsetOf(PStruct, "u1_b"));
157 try expectEqual(1, @offsetOf(PStruct, "u3_a"));
158 try expectEqual(9, @bitOffsetOf(PStruct, "u3_a"));
159 try expectEqual(1, @offsetOf(PStruct, "u10_a"));
160 try expectEqual(12, @bitOffsetOf(PStruct, "u10_a"));
161 try expectEqual(2, @offsetOf(PStruct, "u10_b"));
162 try expectEqual(22, @bitOffsetOf(PStruct, "u10_b"));
163 try expectEqual(4, @sizeOf(PStruct));
164
165 const s1 = @as(PStruct, @bitCast(@as(u32, 0x12345678)));
166 try expectEqual(false, s1.bool_a);
167 try expectEqual(false, s1.bool_b);
168 try expectEqual(false, s1.bool_c);
169 try expectEqual(true, s1.bool_d);
170 try expectEqual(true, s1.bool_e);
171 try expectEqual(true, s1.bool_f);
172 try expectEqual(1, s1.u1_a);
173 try expectEqual(false, s1.bool_g);
174 try expectEqual(0, s1.u1_b);
175 try expectEqual(3, s1.u3_a);
176 try expectEqual(0b1101000101, s1.u10_a);
177 try expectEqual(0b0001001000, s1.u10_b);
178
179 const s2 = @as(packed struct { x: u1, y: u7, z: u24 }, @bitCast(@as(u32, 0xd5c71ff4)));
180 try expectEqual(0, s2.x);
181 try expectEqual(0b1111010, s2.y);
182 try expectEqual(0xd5c71f, s2.z);
183}
184
185test "nested packed structs" {
186 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
188
189 const S1 = packed struct { a: u8, b: u8, c: u8 };
190
191 const S2 = packed struct { d: u8, e: u8, f: u8 };
192
193 const S3 = packed struct { x: S1, y: S2 };
194 const S3Padded = packed struct { s3: S3, pad: u16 };
195
196 try expectEqual(48, @bitSizeOf(S3));
197 try expectEqual(@sizeOf(u48), @sizeOf(S3));
198
199 try expectEqual(3, @offsetOf(S3, "y"));
200 try expectEqual(24, @bitOffsetOf(S3, "y"));
201
202 const s3 = @as(S3Padded, @bitCast(@as(u64, 0xe952d5c71ff4))).s3;
203 try expectEqual(0xf4, s3.x.a);
204 try expectEqual(0x1f, s3.x.b);
205 try expectEqual(0xc7, s3.x.c);
206 try expectEqual(0xd5, s3.y.d);
207 try expectEqual(0x52, s3.y.e);
208 try expectEqual(0xe9, s3.y.f);
209
210 const S4 = packed struct { a: i32, b: i8 };
211 const S5 = packed struct { a: i32, b: i8, c: S4 };
212 const S6 = packed struct { a: i32, b: S4, c: i8 };
213
214 const expectedBitSize = 80;
215 const expectedByteSize = @sizeOf(u80);
216 try expectEqual(expectedBitSize, @bitSizeOf(S5));
217 try expectEqual(expectedByteSize, @sizeOf(S5));
218 try expectEqual(expectedBitSize, @bitSizeOf(S6));
219 try expectEqual(expectedByteSize, @sizeOf(S6));
220
221 try expectEqual(5, @offsetOf(S5, "c"));
222 try expectEqual(40, @bitOffsetOf(S5, "c"));
223 try expectEqual(9, @offsetOf(S6, "c"));
224 try expectEqual(72, @bitOffsetOf(S6, "c"));
225}
226
227test "regular in irregular packed struct" {
228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
230 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
231 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
232
233 const Irregular = packed struct {
234 bar: Regular = Regular{},
235 _: u24 = 0,
236 pub const Regular = packed struct { a: u16 = 0, b: u8 = 0 };
237 };
238
239 var foo = Irregular{};
240 foo.bar.a = 235;
241 foo.bar.b = 42;
242
243 try expectEqual(235, foo.bar.a);
244 try expectEqual(42, foo.bar.b);
245}
246
247test "nested packed struct unaligned" {
248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
251
252 const S1 = packed struct {
253 a: u4,
254 b: u4,
255 c: u8,
256 };
257 const S2 = packed struct {
258 base: u8,
259 p0: S1,
260 bit0: u1,
261 p1: packed struct {
262 a: u8,
263 },
264 p2: packed struct {
265 a: u7,
266 b: u8,
267 },
268 p3: S1,
269
270 var s: @This() = .{
271 .base = 1,
272 .p0 = .{ .a = 2, .b = 3, .c = 4 },
273 .bit0 = 0,
274 .p1 = .{ .a = 5 },
275 .p2 = .{ .a = 6, .b = 7 },
276 .p3 = .{ .a = 8, .b = 9, .c = 10 },
277 };
278 };
279
280 try expect(S2.s.base == 1);
281 try expect(S2.s.p0.a == 2);
282 try expect(S2.s.p0.b == 3);
283 try expect(S2.s.p0.c == 4);
284 try expect(S2.s.bit0 == 0);
285 try expect(S2.s.p1.a == 5);
286 try expect(S2.s.p2.a == 6);
287 try expect(S2.s.p2.b == 7);
288 try expect(S2.s.p3.a == 8);
289 try expect(S2.s.p3.b == 9);
290 try expect(S2.s.p3.c == 10);
291
292 const S3 = packed struct {
293 pad: u8,
294 v: u2,
295 s: packed struct {
296 v: u3,
297 s: packed struct {
298 v: u2,
299 s: packed struct {
300 bit0: u1,
301 byte: u8,
302 bit1: u1,
303 },
304 },
305 },
306 var v0: @This() = .{ .pad = 0, .v = 1, .s = .{ .v = 2, .s = .{ .v = 3, .s = .{ .bit0 = 0, .byte = 4, .bit1 = 1 } } } };
307 };
308
309 try expect(S3.v0.v == 1);
310 try expect(S3.v0.s.v == 2);
311 try expect(S3.v0.s.s.v == 3);
312 try expect(S3.v0.s.s.s.bit0 == 0);
313 try expect(S3.v0.s.s.s.byte == 4);
314 try expect(S3.v0.s.s.s.bit1 == 1);
315}
316
317test "byte-aligned field pointer offsets" {
318 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
319 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
320 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
322
323 const S = struct {
324 const A = packed struct {
325 a: u8,
326 b: u8,
327 c: u8,
328 d: u8,
329 };
330
331 const B = packed struct {
332 a: u16,
333 b: u16,
334 };
335
336 fn doTheTest() !void {
337 var a: A = .{
338 .a = 1,
339 .b = 2,
340 .c = 3,
341 .d = 4,
342 };
343
344 comptime assert(@TypeOf(&a.a) == *align(4:0:4) u8);
345 comptime assert(@TypeOf(&a.b) == *align(4:8:4) u8);
346 comptime assert(@TypeOf(&a.c) == *align(4:16:4) u8);
347 comptime assert(@TypeOf(&a.d) == *align(4:24:4) u8);
348
349 try expect(a.a == 1);
350 try expect(a.b == 2);
351 try expect(a.c == 3);
352 try expect(a.d == 4);
353
354 a.a += 1;
355 try expect(a.a == 2);
356 try expect(a.b == 2);
357 try expect(a.c == 3);
358 try expect(a.d == 4);
359
360 a.b += 1;
361 try expect(a.a == 2);
362 try expect(a.b == 3);
363 try expect(a.c == 3);
364 try expect(a.d == 4);
365
366 a.c += 1;
367 try expect(a.a == 2);
368 try expect(a.b == 3);
369 try expect(a.c == 4);
370 try expect(a.d == 4);
371
372 a.d += 1;
373 try expect(a.a == 2);
374 try expect(a.b == 3);
375 try expect(a.c == 4);
376 try expect(a.d == 5);
377
378 var b: B = .{
379 .a = 1,
380 .b = 2,
381 };
382
383 comptime assert(@TypeOf(&b.a) == *align(4:0:4) u16);
384 comptime assert(@TypeOf(&b.b) == *align(4:16:4) u16);
385
386 try expect(b.a == 1);
387 try expect(b.b == 2);
388
389 b.a += 1;
390 try expect(b.a == 2);
391 try expect(b.b == 2);
392
393 b.b += 1;
394 try expect(b.a == 2);
395 try expect(b.b == 3);
396 }
397 };
398
399 try S.doTheTest();
400 try comptime S.doTheTest();
401}
402
403test "nested packed struct field pointers" {
404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
407 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
408 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // ubsan unaligned pointer access
409 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
410
411 const S2 = packed struct {
412 base: u8,
413 p0: packed struct {
414 a: u4,
415 b: u4,
416 c: u8,
417 },
418 bit: u1,
419 p1: packed struct {
420 a: u7,
421 b: u8,
422 },
423
424 var s: @This() = .{ .base = 1, .p0 = .{ .a = 2, .b = 3, .c = 4 }, .bit = 0, .p1 = .{ .a = 5, .b = 6 } };
425 };
426
427 const ptr_base = &S2.s.base;
428 const ptr_p0_a = &S2.s.p0.a;
429 const ptr_p0_b = &S2.s.p0.b;
430 const ptr_p0_c = &S2.s.p0.c;
431 const ptr_p1_a = &S2.s.p1.a;
432 const ptr_p1_b = &S2.s.p1.b;
433 try expectEqual(1, ptr_base.*);
434 try expectEqual(2, ptr_p0_a.*);
435 try expectEqual(3, ptr_p0_b.*);
436 try expectEqual(4, ptr_p0_c.*);
437 try expectEqual(5, ptr_p1_a.*);
438 try expectEqual(6, ptr_p1_b.*);
439}
440
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
462test "@intFromPtr on a packed struct field" {
463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
465 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
466
467 const S = struct {
468 const P = packed struct {
469 x: u8,
470 y: u8,
471 z: u32,
472 };
473
474 var p0: P = P{
475 .x = 1,
476 .y = 2,
477 .z = 0,
478 };
479 };
480 try expect(@intFromPtr(&S.p0.z) - @intFromPtr(&S.p0.x) == 0);
481}
482
483test "@intFromPtr on a packed struct field unaligned and nested" {
484 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
485 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
487
488 const S1 = packed struct {
489 a: u4,
490 b: u4,
491 c: u8,
492 };
493 const S2 = packed struct {
494 base: u8,
495 p0: S1,
496 bit0: u1,
497 p1: packed struct {
498 a: u8,
499 },
500 p2: packed struct {
501 a: u7,
502 b: u8,
503 },
504 p3: S1,
505
506 var s: @This() = .{
507 .base = 1,
508 .p0 = .{ .a = 2, .b = 3, .c = 4 },
509 .bit0 = 0,
510 .p1 = .{ .a = 5 },
511 .p2 = .{ .a = 6, .b = 7 },
512 .p3 = .{ .a = 8, .b = 9, .c = 10 },
513 };
514 };
515
516 switch (comptime @alignOf(S2)) {
517 4 => {
518 comptime assert(@TypeOf(&S2.s.base) == *align(4) u8);
519 comptime assert(@TypeOf(&S2.s.p0.a) == *align(1:0:2) u4);
520 comptime assert(@TypeOf(&S2.s.p0.b) == *align(1:4:2) u4);
521 comptime assert(@TypeOf(&S2.s.p0.c) == *u8);
522 comptime assert(@TypeOf(&S2.s.bit0) == *align(4:24:8) u1);
523 comptime assert(@TypeOf(&S2.s.p1.a) == *align(4:25:8) u8);
524 comptime assert(@TypeOf(&S2.s.p2.a) == *align(4:33:8) u7);
525 comptime assert(@TypeOf(&S2.s.p2.b) == *u8);
526 comptime assert(@TypeOf(&S2.s.p3.a) == *align(2:0:2) u4);
527 comptime assert(@TypeOf(&S2.s.p3.b) == *align(2:4:2) u4);
528 comptime assert(@TypeOf(&S2.s.p3.c) == *u8);
529 },
530 8 => {
531 comptime assert(@TypeOf(&S2.s.base) == *align(8) u8);
532 comptime assert(@TypeOf(&S2.s.p0.a) == *align(1:0:2) u4);
533 comptime assert(@TypeOf(&S2.s.p0.b) == *align(1:4:2) u4);
534 comptime assert(@TypeOf(&S2.s.p0.c) == *u8);
535 comptime assert(@TypeOf(&S2.s.bit0) == *align(8:24:8) u1);
536 comptime assert(@TypeOf(&S2.s.p1.a) == *align(8:25:8) u8);
537 comptime assert(@TypeOf(&S2.s.p2.a) == *align(8:33:8) u7);
538 comptime assert(@TypeOf(&S2.s.p2.b) == *u8);
539 comptime assert(@TypeOf(&S2.s.p3.a) == *align(2:0:2) u4);
540 comptime assert(@TypeOf(&S2.s.p3.b) == *align(2:4:2) u4);
541 comptime assert(@TypeOf(&S2.s.p3.c) == *u8);
542 },
543 else => {},
544 }
545 try expect(@intFromPtr(&S2.s.base) - @intFromPtr(&S2.s) == 0);
546 try expect(@intFromPtr(&S2.s.p0.a) - @intFromPtr(&S2.s) == 0);
547 try expect(@intFromPtr(&S2.s.p0.b) - @intFromPtr(&S2.s) == 0);
548 try expect(@intFromPtr(&S2.s.p0.c) - @intFromPtr(&S2.s) == 0);
549 try expect(@intFromPtr(&S2.s.bit0) - @intFromPtr(&S2.s) == 0);
550 try expect(@intFromPtr(&S2.s.p1.a) - @intFromPtr(&S2.s) == 0);
551 try expect(@intFromPtr(&S2.s.p2.a) - @intFromPtr(&S2.s) == 0);
552 try expect(@intFromPtr(&S2.s.p2.b) - @intFromPtr(&S2.s) == 0);
553 try expect(@intFromPtr(&S2.s.p3.a) - @intFromPtr(&S2.s) == 0);
554 try expect(@intFromPtr(&S2.s.p3.b) - @intFromPtr(&S2.s) == 0);
555 try expect(@intFromPtr(&S2.s.p3.c) - @intFromPtr(&S2.s) == 0);
556
557 const S3 = packed struct {
558 pad: u8,
559 v: u2,
560 s: packed struct {
561 v: u3,
562 s: packed struct {
563 v: u2,
564 s: packed struct {
565 bit0: u1,
566 byte: u8,
567 bit1: u1,
568 },
569 },
570 },
571 var v0: @This() = .{ .pad = 0, .v = 1, .s = .{ .v = 2, .s = .{ .v = 3, .s = .{ .bit0 = 0, .byte = 4, .bit1 = 1 } } } };
572 };
573
574 comptime assert(@TypeOf(&S3.v0.v) == *align(4:8:4) u2);
575 comptime assert(@TypeOf(&S3.v0.s.v) == *align(4:10:4) u3);
576 comptime assert(@TypeOf(&S3.v0.s.s.v) == *align(4:13:4) u2);
577 comptime assert(@TypeOf(&S3.v0.s.s.s.bit0) == *align(4:15:4) u1);
578 comptime assert(@TypeOf(&S3.v0.s.s.s.byte) == *align(4:16:4) u8);
579 comptime assert(@TypeOf(&S3.v0.s.s.s.bit1) == *align(4:24:4) u1);
580 try expect(@intFromPtr(&S3.v0.v) - @intFromPtr(&S3.v0) == 0);
581 try expect(@intFromPtr(&S3.v0.s) - @intFromPtr(&S3.v0) == 0);
582 try expect(@intFromPtr(&S3.v0.s.v) - @intFromPtr(&S3.v0) == 0);
583 try expect(@intFromPtr(&S3.v0.s.s) - @intFromPtr(&S3.v0) == 0);
584 try expect(@intFromPtr(&S3.v0.s.s.v) - @intFromPtr(&S3.v0) == 0);
585 try expect(@intFromPtr(&S3.v0.s.s.s) - @intFromPtr(&S3.v0) == 0);
586 try expect(@intFromPtr(&S3.v0.s.s.s.bit0) - @intFromPtr(&S3.v0) == 0);
587 try expect(@intFromPtr(&S3.v0.s.s.s.byte) - @intFromPtr(&S3.v0) == 0);
588 try expect(@intFromPtr(&S3.v0.s.s.s.bit1) - @intFromPtr(&S3.v0) == 0);
589}
590
591test "packed struct fields modification" {
592 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
593 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
594
595 // Originally reported at https://github.com/ziglang/zig/issues/16615
596 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
597
598 const Small = packed struct {
599 val: u8 = 0,
600 lo: u4 = 0,
601 hi: u4 = 0,
602
603 var p: @This() = undefined;
604 };
605 Small.p = .{
606 .val = 0x12,
607 .lo = 3,
608 .hi = 4,
609 };
610 try expect(@as(u16, @bitCast(Small.p)) == 0x4312);
611
612 Small.p.val -= Small.p.lo;
613 Small.p.val += Small.p.hi;
614 Small.p.hi -= Small.p.lo;
615 try expect(@as(u16, @bitCast(Small.p)) == 0x1313);
616}
617
618test "optional pointer in packed struct" {
619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
621 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
622 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
623 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
624
625 const T = packed struct { ptr: ?*const u8 };
626 var n: u8 = 0;
627 const x = T{ .ptr = &n };
628 try expect(x.ptr.? == &n);
629}
630
631test "nested packed struct field access test" {
632 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
633 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits
634 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
635 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
636 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
637 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
638 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
639
640 const Vec2 = packed struct {
641 x: f32,
642 y: f32,
643 };
644
645 const Vec3 = packed struct {
646 x: f32,
647 y: f32,
648 z: f32,
649 };
650
651 const NestedVec2 = packed struct {
652 nested: Vec2,
653 };
654
655 const NestedVec3 = packed struct {
656 nested: Vec3,
657 };
658
659 const vec2 = Vec2{
660 .x = 1.0,
661 .y = 2.0,
662 };
663
664 try std.testing.expectEqual(vec2.x, 1.0);
665 try std.testing.expectEqual(vec2.y, 2.0);
666
667 var vec2_o: Vec2 = undefined;
668 const vec2_o_ptr: *Vec2 = &vec2_o;
669 vec2_o_ptr.* = vec2;
670
671 try std.testing.expectEqual(vec2_o.x, 1.0);
672 try std.testing.expectEqual(vec2_o.y, 2.0);
673
674 const nested_vec2 = NestedVec2{
675 .nested = Vec2{
676 .x = 1.0,
677 .y = 2.0,
678 },
679 };
680
681 try std.testing.expectEqual(nested_vec2.nested.x, 1.0);
682 try std.testing.expectEqual(nested_vec2.nested.y, 2.0);
683
684 var nested_o: NestedVec2 = undefined;
685 const nested_o_ptr: *NestedVec2 = &nested_o;
686 nested_o_ptr.* = nested_vec2;
687
688 try std.testing.expectEqual(nested_o.nested.x, 1.0);
689 try std.testing.expectEqual(nested_o.nested.y, 2.0);
690
691 const vec3 = Vec3{
692 .x = 1.0,
693 .y = 2.0,
694 .z = 3.0,
695 };
696
697 try std.testing.expectEqual(vec3.x, 1.0);
698 try std.testing.expectEqual(vec3.y, 2.0);
699 try std.testing.expectEqual(vec3.z, 3.0);
700
701 var vec3_o: Vec3 = undefined;
702 const vec3_o_ptr: *Vec3 = &vec3_o;
703 vec3_o_ptr.* = vec3;
704
705 try std.testing.expectEqual(vec3_o.x, 1.0);
706 try std.testing.expectEqual(vec3_o.y, 2.0);
707 try std.testing.expectEqual(vec3_o.z, 3.0);
708
709 const nested_vec3 = NestedVec3{
710 .nested = Vec3{
711 .x = 1.0,
712 .y = 2.0,
713 .z = 3.0,
714 },
715 };
716
717 try std.testing.expectEqual(nested_vec3.nested.x, 1.0);
718 try std.testing.expectEqual(nested_vec3.nested.y, 2.0);
719 try std.testing.expectEqual(nested_vec3.nested.z, 3.0);
720
721 var nested_vec3_o: NestedVec3 = undefined;
722 const nested_vec3_o_ptr: *NestedVec3 = &nested_vec3_o;
723 nested_vec3_o_ptr.* = nested_vec3;
724
725 try std.testing.expectEqual(nested_vec3_o.nested.x, 1.0);
726 try std.testing.expectEqual(nested_vec3_o.nested.y, 2.0);
727 try std.testing.expectEqual(nested_vec3_o.nested.z, 3.0);
728
729 const hld = packed struct {
730 c: u64,
731 d: u32,
732 };
733
734 const mld = packed struct {
735 h: u64,
736 i: u64,
737 };
738
739 const a = packed struct {
740 b: hld,
741 g: mld,
742 };
743
744 var arg = a{ .b = hld{ .c = 1, .d = 2 }, .g = mld{ .h = 6, .i = 8 } };
745 _ = &arg;
746 try std.testing.expect(arg.b.c == 1);
747 try std.testing.expect(arg.b.d == 2);
748 try std.testing.expect(arg.g.h == 6);
749 try std.testing.expect(arg.g.i == 8);
750}
751
752test "nested packed struct at non-zero offset" {
753 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
754 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
755 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
756
757 const Pair = packed struct(u24) {
758 a: u16 = 0,
759 b: u8 = 0,
760 };
761 const A = packed struct {
762 p1: Pair,
763 p2: Pair,
764 };
765
766 var k: u8 = 123;
767 _ = &k;
768 var v: A = .{
769 .p1 = .{ .a = k + 1, .b = k },
770 .p2 = .{ .a = k + 1, .b = k },
771 };
772
773 try expect(v.p1.a == k + 1 and v.p1.b == k);
774 try expect(v.p2.a == k + 1 and v.p2.b == k);
775
776 v.p2.a -= v.p1.a;
777 v.p2.b -= v.p1.b;
778 try expect(v.p2.a == 0 and v.p2.b == 0);
779 try expect(v.p1.a == k + 1 and v.p1.b == k);
780}
781
782test "nested packed struct at non-zero offset 2" {
783 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
784 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
785 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
786 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
787 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits
788 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
789 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
790
791 const S = struct {
792 const Pair = packed struct(u40) {
793 a: u32 = 0,
794 b: u8 = 0,
795 };
796 const A = packed struct {
797 p1: Pair,
798 p2: Pair,
799 c: C,
800 };
801 const C = packed struct {
802 p1: Pair,
803 pad1: u5,
804 p2: Pair,
805 pad2: u3,
806 last: i16,
807 };
808
809 fn doTheTest() !void {
810 var k: u8 = 123;
811 _ = &k;
812 var v: A = .{
813 .p1 = .{ .a = k + 1, .b = k },
814 .p2 = .{ .a = k + 1, .b = k },
815 .c = .{
816 .pad1 = 11,
817 .pad2 = 2,
818 .p1 = .{ .a = k + 1, .b = k },
819 .p2 = .{ .a = k + 1, .b = k },
820 .last = -12345,
821 },
822 };
823
824 try expect(v.p1.a == k + 1 and v.p1.b == k);
825 try expect(v.p2.a == k + 1 and v.p2.b == k);
826 try expect(v.c.p2.a == k + 1 and v.c.p2.b == k);
827 try expect(v.c.p2.a == k + 1 and v.c.p2.b == k);
828 try expect(v.c.last == -12345);
829 try expect(v.c.pad1 == 11 and v.c.pad2 == 2);
830
831 v.p2.a -= v.p1.a;
832 v.p2.b -= v.p1.b;
833 v.c.p2.a -= v.c.p1.a;
834 v.c.p2.b -= v.c.p1.b;
835 v.c.last -|= 32000;
836 try expect(v.p2.a == 0 and v.p2.b == 0);
837 try expect(v.p1.a == k + 1 and v.p1.b == k);
838 try expect(v.c.p2.a == 0 and v.c.p2.b == 0);
839 try expect(v.c.p1.a == k + 1 and v.c.p1.b == k);
840 try expect(v.c.last == -32768);
841 try expect(v.c.pad1 == 11 and v.c.pad2 == 2);
842 }
843 };
844
845 try S.doTheTest();
846 try comptime S.doTheTest();
847}
848
849test "runtime init of unnamed packed struct type" {
850 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
851 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
852 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
853
854 var z: u8 = 123;
855 _ = &z;
856 try (packed struct {
857 x: u8,
858 pub fn m(s: @This()) !void {
859 try expect(s.x == 123);
860 }
861 }{ .x = z }).m();
862}
863
864test "packed struct passed to callconv(.c) function" {
865 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
868 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
869
870 const S = struct {
871 const Packed = packed struct {
872 a: u16,
873 b: bool = true,
874 c: bool = true,
875 d: u46 = 0,
876 };
877
878 fn foo(p: Packed, a1: u64, a2: u64, a3: u64, a4: u64, a5: u64) callconv(.c) bool {
879 return p.a == 12345 and p.b == true and p.c == true and p.d == 0 and a1 == 5 and a2 == 4 and a3 == 3 and a4 == 2 and a5 == 1;
880 }
881 };
882 const result = S.foo(S.Packed{
883 .a = 12345,
884 .b = true,
885 .c = true,
886 }, 5, 4, 3, 2, 1);
887 try expect(result);
888}
889
890test "overaligned pointer to packed struct" {
891 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
892 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
893 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
894 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
895
896 const S = packed struct { a: u32, b: u32 };
897 var foo: S align(4) = .{ .a = 123, .b = 456 };
898 const ptr: *align(4) S = &foo;
899 const ptr_to_a: *align(4:0:8) u32 = &ptr.a;
900 try expect(ptr_to_a.* == 123);
901}
902
903test "packed struct initialized in bitcast" {
904 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
905 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
906 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
907 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
908
909 const T = packed struct { val: u8 };
910 var val: u8 = 123;
911 _ = &val;
912 const t = @as(u8, @bitCast(T{ .val = val }));
913 try expect(t == val);
914}
915
916test "pointer to container level packed struct field" {
917 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
918 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
919 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
920 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
921 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
922
923 const S = packed struct(u32) {
924 test_bit: bool,
925 someother_data: u12,
926 other_test_bit: bool,
927 someother_more_different_data: u12,
928 other_bits: packed struct(u6) {
929 enable_1: bool,
930 enable_2: bool,
931 enable_3: bool,
932 enable_4: bool,
933 enable_5: bool,
934 enable_6: bool,
935 },
936 var arr = [_]u32{0} ** 2;
937 };
938 @as(*S, @ptrCast(&S.arr[0])).other_bits.enable_3 = true;
939 try expect(S.arr[0] == 0x10000000);
940}
941
942test "store undefined to packed result location" {
943 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
944 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
945 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
946
947 var x: u4 = 0;
948 _ = &x;
949 const s = packed struct { x: u4, y: u4 }{ .x = x, .y = if (x > 0) x else undefined };
950 try expectEqual(x, s.x);
951}
952
953// Originally reported at https://github.com/ziglang/zig/issues/9914
954test "bitcast back and forth" {
955 const S = packed struct { one: u6, two: u1 };
956 const s = S{ .one = 0b110101, .two = 0b1 };
957 const u: u7 = @bitCast(s);
958 const s2: S = @bitCast(u);
959 try expect(s.one == s2.one);
960 try expect(s.two == s2.two);
961}
962
963// Originally reported at https://github.com/ziglang/zig/issues/14200
964test "field access of packed struct smaller than its abi size inside struct initialized with rls" {
965 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
966 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
967 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
968
969 const S = struct {
970 ps: packed struct { x: i2, y: i2 },
971
972 fn init(cond: bool) @This() {
973 return .{ .ps = .{ .x = 0, .y = if (cond) 1 else 0 } };
974 }
975 };
976
977 const s = S.init(true);
978 // note: this bug is triggered by the == operator, expectEqual will hide it
979 try expect(@as(i2, 0) == s.ps.x);
980 try expect(@as(i2, 1) == s.ps.y);
981}
982
983// Originally reported at https://github.com/ziglang/zig/issues/14632
984test "modify nested packed struct aligned field" {
985 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
986 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
987 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
988 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
989
990 const Options = packed struct {
991 foo: bool = false,
992 bar: bool = false,
993 pretty_print: packed struct {
994 enabled: bool = false,
995 num_spaces: u4 = 4,
996 space_char: enum(u1) { space, tab } = .space,
997 indent: u8 = 0,
998 } = .{},
999 baz: bool = false,
1000 };
1001
1002 var opts = Options{};
1003 opts.pretty_print.indent += 1;
1004 try std.testing.expectEqual(0b00000000100100000, @as(u17, @bitCast(opts)));
1005 try std.testing.expect(!opts.foo);
1006 try std.testing.expect(!opts.bar);
1007 try std.testing.expect(!opts.pretty_print.enabled);
1008 try std.testing.expectEqual(4, opts.pretty_print.num_spaces);
1009 try std.testing.expectEqual(1, opts.pretty_print.indent);
1010 try std.testing.expect(!opts.baz);
1011}
1012
1013// Originally reported at https://github.com/ziglang/zig/issues/9674
1014test "assigning packed struct inside another packed struct" {
1015 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1016 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1017 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1018
1019 const S = struct {
1020 const Inner = packed struct {
1021 bits: u3,
1022 more_bits: u6,
1023 };
1024
1025 const Outer = packed struct {
1026 padding: u5,
1027 inner: Inner,
1028 };
1029 fn t(inner: Inner) void {
1030 r.inner = inner;
1031 }
1032
1033 var mem: Outer = undefined;
1034 var r: *volatile Outer = &mem;
1035 };
1036
1037 const val = S.Inner{ .bits = 1, .more_bits = 11 };
1038 S.mem.padding = 0;
1039 S.t(val);
1040
1041 try expectEqual(val, S.mem.inner);
1042 try expect(S.mem.padding == 0);
1043}
1044
1045test "packed struct acts as a namespace" {
1046 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1047
1048 const Bar = packed struct {
1049 const Baz = enum {
1050 fizz,
1051 buzz,
1052 };
1053 };
1054 var foo = Bar.Baz.fizz;
1055 _ = &foo;
1056 try expect(foo == .fizz);
1057}
1058
1059test "pointer loaded correctly from packed struct" {
1060 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1061 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1062 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1063 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1064 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1065
1066 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
1067
1068 const RAM = struct {
1069 data: [0xFFFF + 1]u8,
1070 fn new() !@This() {
1071 return .{ .data = [_]u8{0} ** 0x10000 };
1072 }
1073 fn get(self: *@This(), addr: u16) u8 {
1074 return self.data[addr];
1075 }
1076 };
1077
1078 const CPU = packed struct {
1079 interrupts: bool,
1080 ram: *RAM,
1081 fn new(ram: *RAM) !@This() {
1082 return .{
1083 .ram = ram,
1084 .interrupts = false,
1085 };
1086 }
1087 fn tick(self: *@This()) !void {
1088 const queued_interrupts = self.ram.get(0xFFFF) & self.ram.get(0xFF0F);
1089 if (self.interrupts and queued_interrupts != 0) {
1090 self.interrupts = false;
1091 }
1092 }
1093 };
1094
1095 var ram = try RAM.new();
1096 var cpu = try CPU.new(&ram);
1097 try cpu.tick();
1098 try std.testing.expect(cpu.interrupts == false);
1099}
1100
1101test "assignment to non-byte-aligned field in packed struct" {
1102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1103 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1104 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1105 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
1106
1107 const Frame = packed struct {
1108 num: u20,
1109 };
1110
1111 const Entry = packed struct {
1112 other: u12,
1113 frame: Frame,
1114 };
1115
1116 const frame = Frame{ .num = 0x7FDE };
1117 var entry = Entry{ .other = 0, .frame = .{ .num = 0xFFFFF } };
1118 entry.frame = frame;
1119 try expect(entry.frame.num == 0x7FDE);
1120}
1121
1122test "packed struct field pointer aligned properly" {
1123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1125 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
1126
1127 const Foo = packed struct {
1128 a: i32,
1129 b: u8,
1130
1131 var buffer: [256]u8 = undefined;
1132 };
1133
1134 var f1: *align(16) Foo = @alignCast(@as(*align(1) Foo, @ptrCast(&Foo.buffer[0])));
1135 try expect(@typeInfo(@TypeOf(f1)).pointer.alignment == 16);
1136 try expect(@intFromPtr(f1) == @intFromPtr(&f1.a));
1137 try expect(@typeInfo(@TypeOf(&f1.a)).pointer.alignment == 16);
1138}
1139
1140test "load flag from packed struct in union" {
1141 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1142 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1144 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1145 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1146
1147 const A = packed struct {
1148 a: bool,
1149 b: bool,
1150 c: bool,
1151 d: bool,
1152
1153 e: bool,
1154 f: bool,
1155 g: bool,
1156 h: bool,
1157 };
1158
1159 const X = union {
1160 x: A,
1161 y: u64,
1162
1163 pub fn a(_: i32, _: i32, _: i32, _: i32, _: i32, _: bool, flag_b: bool) !void {
1164 const flag_b_byte: u8 = @intFromBool(flag_b);
1165 try std.testing.expect(flag_b_byte == 1);
1166 }
1167 pub fn b(x: *@This()) !void {
1168 try a(0, 1, 2, 3, 4, x.x.a, x.x.b);
1169 }
1170 };
1171 var flags = A{
1172 .a = false,
1173 .b = true,
1174 .c = false,
1175 .d = false,
1176
1177 .e = false,
1178 .f = true,
1179 .g = false,
1180 .h = false,
1181 };
1182 _ = &flags;
1183 var x = X{
1184 .x = flags,
1185 };
1186 try X.b(&x);
1187 comptime if (@sizeOf(A) != 1) unreachable;
1188}
1189
1190test "bitcasting a packed struct at comptime and using the result" {
1191 comptime {
1192 const Struct = packed struct {
1193 x: packed union {
1194 a: u63,
1195 b: packed struct(u63) {
1196 a: i32,
1197 b: u31 = 0,
1198 },
1199 },
1200 y: u1,
1201
1202 pub fn bitcast(fd: u64) @This() {
1203 return @bitCast(fd);
1204 }
1205
1206 pub fn cannotReach(_: @This()) i32 {
1207 return 0;
1208 }
1209 };
1210
1211 _ = Struct.bitcast(@as(u64, 0)).cannotReach();
1212 }
1213}
1214
1215test "2-byte packed struct argument in C calling convention" {
1216 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1218 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1219 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1220
1221 const S = packed struct(u16) {
1222 x: u15 = 0,
1223 y: u1 = 0,
1224
1225 fn foo(s: @This()) callconv(.c) i32 {
1226 return s.x;
1227 }
1228 fn bar(s: @This()) !void {
1229 try expect(foo(s) == 1);
1230 }
1231 };
1232 {
1233 var s: S = .{};
1234 s.x += 1;
1235 try S.bar(s);
1236 }
1237 comptime {
1238 var s: S = .{};
1239 s.x += 1;
1240 try S.bar(s);
1241 }
1242}
1243
1244test "packed struct contains optional pointer" {
1245 const foo: packed struct {
1246 a: ?*@This() = null,
1247 } = .{};
1248 try expect(foo.a == null);
1249}
1250
1251test "packed struct equality" {
1252 const Foo = packed struct {
1253 a: u4,
1254 b: u4,
1255 };
1256
1257 const S = struct {
1258 fn doTest(x: Foo, y: Foo) !void {
1259 try expect(x == y);
1260 try expect(!(x != y));
1261 }
1262 };
1263
1264 const x: Foo = .{ .a = 1, .b = 2 };
1265 const y: Foo = .{ .b = 2, .a = 1 };
1266
1267 try S.doTest(x, y);
1268 comptime try S.doTest(x, y);
1269}
1270
1271test "packed struct equality ignores padding bits" {
1272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1273 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1274 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1275
1276 const S = packed struct { b: bool };
1277 var s: S = undefined;
1278 s.b = true;
1279 try std.testing.expect(s != S{ .b = false });
1280 try std.testing.expect(s == S{ .b = true });
1281}
1282
1283test "packed struct with signed field" {
1284 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1285 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1286
1287 var s: packed struct {
1288 a: i2,
1289 b: u6,
1290 } = .{ .a = -1, .b = 42 };
1291 s = s;
1292 try expect(s.a == -1);
1293 try expect(s.b == 42);
1294}
1295
1296test "assign packed struct initialized with RLS to packed struct literal field" {
1297 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1298 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) return error.SkipZigTest;
1299 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1300 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1301
1302 const Inner = packed struct { x: u17 };
1303 const Outer = packed struct { inner: Inner, x: u15 };
1304
1305 var x: u15 = undefined;
1306 x = 23385;
1307 var inner: Inner = undefined;
1308 inner = .{ .x = x };
1309 const outer = Outer{ .x = x, .inner = inner };
1310 try expect(outer.inner.x == x);
1311 try expect(outer.x == x);
1312}
1313
1314test "byte-aligned packed relocation" {
1315 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1316 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
1317 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1318 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1319 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1320
1321 const S = struct {
1322 var global: u8 align(2) = 0;
1323 var packed_value: packed struct { x: u8, y: *align(2) u8 } = .{ .x = 111, .y = &global };
1324 };
1325 try expect(S.packed_value.x == 111);
1326 try expect(S.packed_value.y == &S.global);
1327}
1328
1329test "packed struct store of comparison result" {
1330 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1331 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1332 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
1333
1334 const S1 = packed struct {
1335 val1: u3,
1336 val2: u3,
1337 };
1338 const S2 = packed struct {
1339 a: bool,
1340 b: bool,
1341 };
1342
1343 var A: S1 = .{ .val1 = 1, .val2 = 1 };
1344 A.val2 += 1;
1345 try expectEqual(1, A.val1);
1346 try expectEqual(2, A.val2);
1347 try expect((A.val2 & 1) != 1);
1348 const result1: S2 = .{ .a = (A.val2 & 1) != 1, .b = (A.val1 & 1) != 1 };
1349 try expect(result1.a);
1350 try expect(!result1.b);
1351
1352 try expect((A.val2 == 3) == false);
1353 try expect((A.val2 == 2) == true);
1354 const result2: S2 = .{ .a = !(A.val2 == 3), .b = (A.val1 == 2) };
1355 try expect(result2.a);
1356 try expect(!result2.b);
1357}