blob a8665a02 (36128B) - Raw
1 const std = @import("std"); 2 const builtin = @import("builtin"); 3 const assert = std.debug.assert; 4 const expect = std.testing.expect; 5 const expectEqual = std.testing.expectEqual; 6 const native_endian = builtin.cpu.arch.endian(); 7 8 test "flags in packed structs" { 9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 10 11 const Flags1 = packed struct { 12 // first 8 bits 13 b0_0: u1, 14 b0_1: u1, 15 b0_2: u1, 16 b0_3: u1, 17 b0_4: u1, 18 b0_5: u1, 19 b0_6: u1, 20 b0_7: u1, 21 22 // 7 more bits 23 b1_0: u1, 24 b1_1: u1, 25 b1_2: u1, 26 b1_3: u1, 27 b1_4: u1, 28 b1_5: u1, 29 b1_6: u1, 30 31 // some padding to fill to 24 bits 32 _: u9, 33 }; 34 35 try expectEqual(@sizeOf(u24), @sizeOf(Flags1)); 36 try expectEqual(24, @bitSizeOf(Flags1)); 37 38 const Flags2 = packed struct { 39 // byte 0 40 b0_0: u1, 41 b0_1: u1, 42 b0_2: u1, 43 b0_3: u1, 44 b0_4: u1, 45 b0_5: u1, 46 b0_6: u1, 47 b0_7: u1, 48 49 // partial byte 1 (but not 8 bits) 50 b1_0: u1, 51 b1_1: u1, 52 b1_2: u1, 53 b1_3: u1, 54 b1_4: u1, 55 b1_5: u1, 56 b1_6: u1, 57 58 // some padding that should yield @sizeOf(Flags2) == 4 59 _: u10, 60 }; 61 62 try expectEqual(@sizeOf(u25), @sizeOf(Flags2)); 63 try expectEqual(25, @bitSizeOf(Flags2)); 64 65 const Flags3 = packed struct { 66 // byte 0 67 b0_0: u1, 68 b0_1: u1, 69 b0_2: u1, 70 b0_3: u1, 71 b0_4: u1, 72 b0_5: u1, 73 b0_6: u1, 74 b0_7: u1, 75 76 // byte 1 77 b1_0: u1, 78 b1_1: u1, 79 b1_2: u1, 80 b1_3: u1, 81 b1_4: u1, 82 b1_5: u1, 83 b1_6: u1, 84 b1_7: u1, 85 86 // some padding that should yield @sizeOf(Flags2) == 4 87 _: u16, // it works, if the padding is 8-based 88 }; 89 90 try expectEqual(@sizeOf(u32), @sizeOf(Flags3)); 91 try expectEqual(32, @bitSizeOf(Flags3)); 92 } 93 94 test "consistent size of packed structs" { 95 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 96 97 const TxData1 = packed struct { data: u8, _23: u23, full: bool = false }; 98 const TxData2 = packed struct { data: u9, _22: u22, full: bool = false }; 99 100 const register_size_bits = 32; 101 const register_size_bytes = @sizeOf(u32); 102 103 try expectEqual(register_size_bits, @bitSizeOf(TxData1)); 104 try expectEqual(register_size_bytes, @sizeOf(TxData1)); 105 106 try expectEqual(register_size_bits, @bitSizeOf(TxData2)); 107 try expectEqual(register_size_bytes, @sizeOf(TxData2)); 108 109 const TxData4 = packed struct { a: u32, b: u24 }; 110 const TxData6 = packed struct { a: u24, b: u32 }; 111 112 const expectedBitSize = 56; 113 const expectedByteSize = @sizeOf(u56); 114 115 try expectEqual(expectedBitSize, @bitSizeOf(TxData4)); 116 try expectEqual(expectedByteSize, @sizeOf(TxData4)); 117 118 try expectEqual(expectedBitSize, @bitSizeOf(TxData6)); 119 try expectEqual(expectedByteSize, @sizeOf(TxData6)); 120 } 121 122 test "correct sizeOf and offsets in packed structs" { 123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO 124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO 125 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 126 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 127 128 const PStruct = packed struct { 129 bool_a: bool, 130 bool_b: bool, 131 bool_c: bool, 132 bool_d: bool, 133 bool_e: bool, 134 bool_f: bool, 135 u1_a: u1, 136 bool_g: bool, 137 u1_b: u1, 138 u3_a: u3, 139 u10_a: u10, 140 u10_b: u10, 141 }; 142 try expectEqual(0, @offsetOf(PStruct, "bool_a")); 143 try expectEqual(0, @bitOffsetOf(PStruct, "bool_a")); 144 try expectEqual(0, @offsetOf(PStruct, "bool_b")); 145 try expectEqual(1, @bitOffsetOf(PStruct, "bool_b")); 146 try expectEqual(0, @offsetOf(PStruct, "bool_c")); 147 try expectEqual(2, @bitOffsetOf(PStruct, "bool_c")); 148 try expectEqual(0, @offsetOf(PStruct, "bool_d")); 149 try expectEqual(3, @bitOffsetOf(PStruct, "bool_d")); 150 try expectEqual(0, @offsetOf(PStruct, "bool_e")); 151 try expectEqual(4, @bitOffsetOf(PStruct, "bool_e")); 152 try expectEqual(0, @offsetOf(PStruct, "bool_f")); 153 try expectEqual(5, @bitOffsetOf(PStruct, "bool_f")); 154 try expectEqual(0, @offsetOf(PStruct, "u1_a")); 155 try expectEqual(6, @bitOffsetOf(PStruct, "u1_a")); 156 try expectEqual(0, @offsetOf(PStruct, "bool_g")); 157 try expectEqual(7, @bitOffsetOf(PStruct, "bool_g")); 158 try expectEqual(1, @offsetOf(PStruct, "u1_b")); 159 try expectEqual(8, @bitOffsetOf(PStruct, "u1_b")); 160 try expectEqual(1, @offsetOf(PStruct, "u3_a")); 161 try expectEqual(9, @bitOffsetOf(PStruct, "u3_a")); 162 try expectEqual(1, @offsetOf(PStruct, "u10_a")); 163 try expectEqual(12, @bitOffsetOf(PStruct, "u10_a")); 164 try expectEqual(2, @offsetOf(PStruct, "u10_b")); 165 try expectEqual(22, @bitOffsetOf(PStruct, "u10_b")); 166 try expectEqual(4, @sizeOf(PStruct)); 167 168 if (native_endian == .little) { 169 const s1 = @as(PStruct, @bitCast(@as(u32, 0x12345678))); 170 try expectEqual(false, s1.bool_a); 171 try expectEqual(false, s1.bool_b); 172 try expectEqual(false, s1.bool_c); 173 try expectEqual(true, s1.bool_d); 174 try expectEqual(true, s1.bool_e); 175 try expectEqual(true, s1.bool_f); 176 try expectEqual(@as(u1, 1), s1.u1_a); 177 try expectEqual(false, s1.bool_g); 178 try expectEqual(@as(u1, 0), s1.u1_b); 179 try expectEqual(@as(u3, 3), s1.u3_a); 180 try expectEqual(@as(u10, 0b1101000101), s1.u10_a); 181 try expectEqual(@as(u10, 0b0001001000), s1.u10_b); 182 183 const s2 = @as(packed struct { x: u1, y: u7, z: u24 }, @bitCast(@as(u32, 0xd5c71ff4))); 184 try expectEqual(@as(u1, 0), s2.x); 185 try expectEqual(@as(u7, 0b1111010), s2.y); 186 try expectEqual(@as(u24, 0xd5c71f), s2.z); 187 } 188 } 189 190 test "nested packed structs" { 191 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO 192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO 193 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 194 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 195 196 const S1 = packed struct { a: u8, b: u8, c: u8 }; 197 198 const S2 = packed struct { d: u8, e: u8, f: u8 }; 199 200 const S3 = packed struct { x: S1, y: S2 }; 201 const S3Padded = packed struct { s3: S3, pad: u16 }; 202 203 try expectEqual(48, @bitSizeOf(S3)); 204 try expectEqual(@sizeOf(u48), @sizeOf(S3)); 205 206 try expectEqual(3, @offsetOf(S3, "y")); 207 try expectEqual(24, @bitOffsetOf(S3, "y")); 208 209 if (native_endian == .little) { 210 const s3 = @as(S3Padded, @bitCast(@as(u64, 0xe952d5c71ff4))).s3; 211 try expectEqual(@as(u8, 0xf4), s3.x.a); 212 try expectEqual(@as(u8, 0x1f), s3.x.b); 213 try expectEqual(@as(u8, 0xc7), s3.x.c); 214 try expectEqual(@as(u8, 0xd5), s3.y.d); 215 try expectEqual(@as(u8, 0x52), s3.y.e); 216 try expectEqual(@as(u8, 0xe9), s3.y.f); 217 } 218 219 const S4 = packed struct { a: i32, b: i8 }; 220 const S5 = packed struct { a: i32, b: i8, c: S4 }; 221 const S6 = packed struct { a: i32, b: S4, c: i8 }; 222 223 const expectedBitSize = 80; 224 const expectedByteSize = @sizeOf(u80); 225 try expectEqual(expectedBitSize, @bitSizeOf(S5)); 226 try expectEqual(expectedByteSize, @sizeOf(S5)); 227 try expectEqual(expectedBitSize, @bitSizeOf(S6)); 228 try expectEqual(expectedByteSize, @sizeOf(S6)); 229 230 try expectEqual(5, @offsetOf(S5, "c")); 231 try expectEqual(40, @bitOffsetOf(S5, "c")); 232 try expectEqual(9, @offsetOf(S6, "c")); 233 try expectEqual(72, @bitOffsetOf(S6, "c")); 234 } 235 236 test "regular in irregular packed struct" { 237 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 238 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 239 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 240 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 241 242 const Irregular = packed struct { 243 bar: Regular = Regular{}, 244 _: u24 = 0, 245 pub const Regular = packed struct { a: u16 = 0, b: u8 = 0 }; 246 }; 247 248 var foo = Irregular{}; 249 foo.bar.a = 235; 250 foo.bar.b = 42; 251 252 try expectEqual(@as(u16, 235), foo.bar.a); 253 try expectEqual(@as(u8, 42), foo.bar.b); 254 } 255 256 test "nested packed struct unaligned" { 257 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 260 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 261 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet 262 263 const S1 = packed struct { 264 a: u4, 265 b: u4, 266 c: u8, 267 }; 268 const S2 = packed struct { 269 base: u8, 270 p0: S1, 271 bit0: u1, 272 p1: packed struct { 273 a: u8, 274 }, 275 p2: packed struct { 276 a: u7, 277 b: u8, 278 }, 279 p3: S1, 280 281 var s: @This() = .{ 282 .base = 1, 283 .p0 = .{ .a = 2, .b = 3, .c = 4 }, 284 .bit0 = 0, 285 .p1 = .{ .a = 5 }, 286 .p2 = .{ .a = 6, .b = 7 }, 287 .p3 = .{ .a = 8, .b = 9, .c = 10 }, 288 }; 289 }; 290 291 try expect(S2.s.base == 1); 292 try expect(S2.s.p0.a == 2); 293 try expect(S2.s.p0.b == 3); 294 try expect(S2.s.p0.c == 4); 295 try expect(S2.s.bit0 == 0); 296 try expect(S2.s.p1.a == 5); 297 try expect(S2.s.p2.a == 6); 298 try expect(S2.s.p2.b == 7); 299 try expect(S2.s.p3.a == 8); 300 try expect(S2.s.p3.b == 9); 301 try expect(S2.s.p3.c == 10); 302 303 const S3 = packed struct { 304 pad: u8, 305 v: u2, 306 s: packed struct { 307 v: u3, 308 s: packed struct { 309 v: u2, 310 s: packed struct { 311 bit0: u1, 312 byte: u8, 313 bit1: u1, 314 }, 315 }, 316 }, 317 var v0: @This() = .{ .pad = 0, .v = 1, .s = .{ .v = 2, .s = .{ .v = 3, .s = .{ .bit0 = 0, .byte = 4, .bit1 = 1 } } } }; 318 }; 319 320 try expect(S3.v0.v == 1); 321 try expect(S3.v0.s.v == 2); 322 try expect(S3.v0.s.s.v == 3); 323 try expect(S3.v0.s.s.s.bit0 == 0); 324 try expect(S3.v0.s.s.s.byte == 4); 325 try expect(S3.v0.s.s.s.bit1 == 1); 326 } 327 328 test "byte-aligned field pointer offsets" { 329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 332 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 333 334 const S = struct { 335 const A = packed struct { 336 a: u8, 337 b: u8, 338 c: u8, 339 d: u8, 340 }; 341 342 const B = packed struct { 343 a: u16, 344 b: u16, 345 }; 346 347 fn doTheTest() !void { 348 var a: A = .{ 349 .a = 1, 350 .b = 2, 351 .c = 3, 352 .d = 4, 353 }; 354 switch (comptime builtin.cpu.arch.endian()) { 355 .little => { 356 comptime assert(@TypeOf(&a.a) == *align(4) u8); 357 comptime assert(@TypeOf(&a.b) == *u8); 358 comptime assert(@TypeOf(&a.c) == *align(2) u8); 359 comptime assert(@TypeOf(&a.d) == *u8); 360 }, 361 .big => { 362 // TODO re-evaluate packed struct endianness 363 comptime assert(@TypeOf(&a.a) == *align(4:0:4) u8); 364 comptime assert(@TypeOf(&a.b) == *align(4:8:4) u8); 365 comptime assert(@TypeOf(&a.c) == *align(4:16:4) u8); 366 comptime assert(@TypeOf(&a.d) == *align(4:24:4) u8); 367 }, 368 } 369 try expect(a.a == 1); 370 try expect(a.b == 2); 371 try expect(a.c == 3); 372 try expect(a.d == 4); 373 374 a.a += 1; 375 try expect(a.a == 2); 376 try expect(a.b == 2); 377 try expect(a.c == 3); 378 try expect(a.d == 4); 379 380 a.b += 1; 381 try expect(a.a == 2); 382 try expect(a.b == 3); 383 try expect(a.c == 3); 384 try expect(a.d == 4); 385 386 a.c += 1; 387 try expect(a.a == 2); 388 try expect(a.b == 3); 389 try expect(a.c == 4); 390 try expect(a.d == 4); 391 392 a.d += 1; 393 try expect(a.a == 2); 394 try expect(a.b == 3); 395 try expect(a.c == 4); 396 try expect(a.d == 5); 397 398 var b: B = .{ 399 .a = 1, 400 .b = 2, 401 }; 402 switch (comptime builtin.cpu.arch.endian()) { 403 .little => { 404 comptime assert(@TypeOf(&b.a) == *align(4) u16); 405 comptime assert(@TypeOf(&b.b) == *u16); 406 }, 407 .big => { 408 comptime assert(@TypeOf(&b.a) == *align(4:0:4) u16); 409 comptime assert(@TypeOf(&b.b) == *align(4:16:4) u16); 410 }, 411 } 412 try expect(b.a == 1); 413 try expect(b.b == 2); 414 415 b.a += 1; 416 try expect(b.a == 2); 417 try expect(b.b == 2); 418 419 b.b += 1; 420 try expect(b.a == 2); 421 try expect(b.b == 3); 422 } 423 }; 424 425 try S.doTheTest(); 426 try comptime S.doTheTest(); 427 } 428 429 test "nested packed struct field pointers" { 430 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 433 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 434 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // ubsan unaligned pointer access 435 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; 436 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet 437 438 const S2 = packed struct { 439 base: u8, 440 p0: packed struct { 441 a: u4, 442 b: u4, 443 c: u8, 444 }, 445 bit: u1, 446 p1: packed struct { 447 a: u7, 448 b: u8, 449 }, 450 451 var s: @This() = .{ .base = 1, .p0 = .{ .a = 2, .b = 3, .c = 4 }, .bit = 0, .p1 = .{ .a = 5, .b = 6 } }; 452 }; 453 454 const ptr_base = &S2.s.base; 455 const ptr_p0_a = &S2.s.p0.a; 456 const ptr_p0_b = &S2.s.p0.b; 457 const ptr_p0_c = &S2.s.p0.c; 458 const ptr_p1_a = &S2.s.p1.a; 459 const ptr_p1_b = &S2.s.p1.b; 460 try expectEqual(@as(u8, 1), ptr_base.*); 461 try expectEqual(@as(u4, 2), ptr_p0_a.*); 462 try expectEqual(@as(u4, 3), ptr_p0_b.*); 463 try expectEqual(@as(u8, 4), ptr_p0_c.*); 464 try expectEqual(@as(u7, 5), ptr_p1_a.*); 465 try expectEqual(@as(u8, 6), ptr_p1_b.*); 466 } 467 468 test "load pointer from packed struct" { 469 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 471 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 472 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 473 474 const A = struct { 475 index: u16, 476 }; 477 const B = packed struct { 478 x: *A, 479 y: u32, 480 }; 481 var a: A = .{ .index = 123 }; 482 var b_list: []const B = &.{.{ .x = &a, .y = 99 }}; 483 for (b_list) |b| { 484 var i = b.x.index; 485 try expect(i == 123); 486 } 487 } 488 489 test "@intFromPtr on a packed struct field" { 490 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 492 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 493 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 494 if (native_endian != .little) return error.SkipZigTest; 495 496 const S = struct { 497 const P = packed struct { 498 x: u8, 499 y: u8, 500 z: u32, 501 }; 502 503 var p0: P = P{ 504 .x = 1, 505 .y = 2, 506 .z = 0, 507 }; 508 }; 509 try expect(@intFromPtr(&S.p0.z) - @intFromPtr(&S.p0.x) == 2); 510 } 511 512 test "@intFromPtr on a packed struct field unaligned and nested" { 513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 516 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 517 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; 518 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet 519 520 const S1 = packed struct { 521 a: u4, 522 b: u4, 523 c: u8, 524 }; 525 const S2 = packed struct { 526 base: u8, 527 p0: S1, 528 bit0: u1, 529 p1: packed struct { 530 a: u8, 531 }, 532 p2: packed struct { 533 a: u7, 534 b: u8, 535 }, 536 p3: S1, 537 538 var s: @This() = .{ 539 .base = 1, 540 .p0 = .{ .a = 2, .b = 3, .c = 4 }, 541 .bit0 = 0, 542 .p1 = .{ .a = 5 }, 543 .p2 = .{ .a = 6, .b = 7 }, 544 .p3 = .{ .a = 8, .b = 9, .c = 10 }, 545 }; 546 }; 547 548 switch (comptime @alignOf(S2)) { 549 4 => { 550 comptime assert(@TypeOf(&S2.s.base) == *align(4) u8); 551 comptime assert(@TypeOf(&S2.s.p0.a) == *align(1:0:2) u4); 552 comptime assert(@TypeOf(&S2.s.p0.b) == *align(1:4:2) u4); 553 comptime assert(@TypeOf(&S2.s.p0.c) == *u8); 554 comptime assert(@TypeOf(&S2.s.bit0) == *align(4:24:8) u1); 555 comptime assert(@TypeOf(&S2.s.p1.a) == *align(4:25:8) u8); 556 comptime assert(@TypeOf(&S2.s.p2.a) == *align(4:33:8) u7); 557 comptime assert(@TypeOf(&S2.s.p2.b) == *u8); 558 comptime assert(@TypeOf(&S2.s.p3.a) == *align(2:0:2) u4); 559 comptime assert(@TypeOf(&S2.s.p3.b) == *align(2:4:2) u4); 560 comptime assert(@TypeOf(&S2.s.p3.c) == *u8); 561 }, 562 8 => { 563 comptime assert(@TypeOf(&S2.s.base) == *align(8) u8); 564 comptime assert(@TypeOf(&S2.s.p0.a) == *align(1:0:2) u4); 565 comptime assert(@TypeOf(&S2.s.p0.b) == *align(1:4:2) u4); 566 comptime assert(@TypeOf(&S2.s.p0.c) == *u8); 567 comptime assert(@TypeOf(&S2.s.bit0) == *align(8:24:8) u1); 568 comptime assert(@TypeOf(&S2.s.p1.a) == *align(8:25:8) u8); 569 comptime assert(@TypeOf(&S2.s.p2.a) == *align(8:33:8) u7); 570 comptime assert(@TypeOf(&S2.s.p2.b) == *u8); 571 comptime assert(@TypeOf(&S2.s.p3.a) == *align(2:0:2) u4); 572 comptime assert(@TypeOf(&S2.s.p3.b) == *align(2:4:2) u4); 573 comptime assert(@TypeOf(&S2.s.p3.c) == *u8); 574 }, 575 else => {}, 576 } 577 try expect(@intFromPtr(&S2.s.base) - @intFromPtr(&S2.s) == 0); 578 try expect(@intFromPtr(&S2.s.p0.a) - @intFromPtr(&S2.s) == 1); 579 try expect(@intFromPtr(&S2.s.p0.b) - @intFromPtr(&S2.s) == 1); 580 try expect(@intFromPtr(&S2.s.p0.c) - @intFromPtr(&S2.s) == 2); 581 try expect(@intFromPtr(&S2.s.bit0) - @intFromPtr(&S2.s) == 0); 582 try expect(@intFromPtr(&S2.s.p1.a) - @intFromPtr(&S2.s) == 0); 583 try expect(@intFromPtr(&S2.s.p2.a) - @intFromPtr(&S2.s) == 0); 584 try expect(@intFromPtr(&S2.s.p2.b) - @intFromPtr(&S2.s) == 5); 585 try expect(@intFromPtr(&S2.s.p3.a) - @intFromPtr(&S2.s) == 6); 586 try expect(@intFromPtr(&S2.s.p3.b) - @intFromPtr(&S2.s) == 6); 587 try expect(@intFromPtr(&S2.s.p3.c) - @intFromPtr(&S2.s) == 7); 588 589 const S3 = packed struct { 590 pad: u8, 591 v: u2, 592 s: packed struct { 593 v: u3, 594 s: packed struct { 595 v: u2, 596 s: packed struct { 597 bit0: u1, 598 byte: u8, 599 bit1: u1, 600 }, 601 }, 602 }, 603 var v0: @This() = .{ .pad = 0, .v = 1, .s = .{ .v = 2, .s = .{ .v = 3, .s = .{ .bit0 = 0, .byte = 4, .bit1 = 1 } } } }; 604 }; 605 606 comptime assert(@TypeOf(&S3.v0.v) == *align(4:8:4) u2); 607 comptime assert(@TypeOf(&S3.v0.s.v) == *align(4:10:4) u3); 608 comptime assert(@TypeOf(&S3.v0.s.s.v) == *align(4:13:4) u2); 609 comptime assert(@TypeOf(&S3.v0.s.s.s.bit0) == *align(4:15:4) u1); 610 comptime assert(@TypeOf(&S3.v0.s.s.s.byte) == *align(2) u8); 611 comptime assert(@TypeOf(&S3.v0.s.s.s.bit1) == *align(4:24:4) u1); 612 try expect(@intFromPtr(&S3.v0.v) - @intFromPtr(&S3.v0) == 0); 613 try expect(@intFromPtr(&S3.v0.s) - @intFromPtr(&S3.v0) == 0); 614 try expect(@intFromPtr(&S3.v0.s.v) - @intFromPtr(&S3.v0) == 0); 615 try expect(@intFromPtr(&S3.v0.s.s) - @intFromPtr(&S3.v0) == 0); 616 try expect(@intFromPtr(&S3.v0.s.s.v) - @intFromPtr(&S3.v0) == 0); 617 try expect(@intFromPtr(&S3.v0.s.s.s) - @intFromPtr(&S3.v0) == 0); 618 try expect(@intFromPtr(&S3.v0.s.s.s.bit0) - @intFromPtr(&S3.v0) == 0); 619 try expect(@intFromPtr(&S3.v0.s.s.s.byte) - @intFromPtr(&S3.v0) == 2); 620 try expect(@intFromPtr(&S3.v0.s.s.s.bit1) - @intFromPtr(&S3.v0) == 0); 621 } 622 623 test "packed struct fields modification" { 624 // Originally reported at https://github.com/ziglang/zig/issues/16615 625 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 626 627 const Small = packed struct { 628 val: u8 = 0, 629 lo: u4 = 0, 630 hi: u4 = 0, 631 632 var p: @This() = undefined; 633 }; 634 Small.p = .{ 635 .val = 0x12, 636 .lo = 3, 637 .hi = 4, 638 }; 639 try expect(@as(u16, @bitCast(Small.p)) == 0x4312); 640 641 Small.p.val -= Small.p.lo; 642 Small.p.val += Small.p.hi; 643 Small.p.hi -= Small.p.lo; 644 try expect(@as(u16, @bitCast(Small.p)) == 0x1313); 645 } 646 647 test "optional pointer in packed struct" { 648 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 649 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 650 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 651 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 652 653 const T = packed struct { ptr: ?*const u8 }; 654 var n: u8 = 0; 655 const x = T{ .ptr = &n }; 656 try expect(x.ptr.? == &n); 657 } 658 659 test "nested packed struct field access test" { 660 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO 661 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits 662 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO 663 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO 664 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 665 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 666 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest; 667 668 const Vec2 = packed struct { 669 x: f32, 670 y: f32, 671 }; 672 673 const Vec3 = packed struct { 674 x: f32, 675 y: f32, 676 z: f32, 677 }; 678 679 const NestedVec2 = packed struct { 680 nested: Vec2, 681 }; 682 683 const NestedVec3 = packed struct { 684 nested: Vec3, 685 }; 686 687 const vec2 = Vec2{ 688 .x = 1.0, 689 .y = 2.0, 690 }; 691 692 try std.testing.expectEqual(vec2.x, 1.0); 693 try std.testing.expectEqual(vec2.y, 2.0); 694 695 var vec2_o: Vec2 = undefined; 696 const vec2_o_ptr: *Vec2 = &vec2_o; 697 vec2_o_ptr.* = vec2; 698 699 try std.testing.expectEqual(vec2_o.x, 1.0); 700 try std.testing.expectEqual(vec2_o.y, 2.0); 701 702 const nested_vec2 = NestedVec2{ 703 .nested = Vec2{ 704 .x = 1.0, 705 .y = 2.0, 706 }, 707 }; 708 709 try std.testing.expectEqual(nested_vec2.nested.x, 1.0); 710 try std.testing.expectEqual(nested_vec2.nested.y, 2.0); 711 712 var nested_o: NestedVec2 = undefined; 713 const nested_o_ptr: *NestedVec2 = &nested_o; 714 nested_o_ptr.* = nested_vec2; 715 716 try std.testing.expectEqual(nested_o.nested.x, 1.0); 717 try std.testing.expectEqual(nested_o.nested.y, 2.0); 718 719 const vec3 = Vec3{ 720 .x = 1.0, 721 .y = 2.0, 722 .z = 3.0, 723 }; 724 725 try std.testing.expectEqual(vec3.x, 1.0); 726 try std.testing.expectEqual(vec3.y, 2.0); 727 try std.testing.expectEqual(vec3.z, 3.0); 728 729 var vec3_o: Vec3 = undefined; 730 const vec3_o_ptr: *Vec3 = &vec3_o; 731 vec3_o_ptr.* = vec3; 732 733 try std.testing.expectEqual(vec3_o.x, 1.0); 734 try std.testing.expectEqual(vec3_o.y, 2.0); 735 try std.testing.expectEqual(vec3_o.z, 3.0); 736 737 const nested_vec3 = NestedVec3{ 738 .nested = Vec3{ 739 .x = 1.0, 740 .y = 2.0, 741 .z = 3.0, 742 }, 743 }; 744 745 try std.testing.expectEqual(nested_vec3.nested.x, 1.0); 746 try std.testing.expectEqual(nested_vec3.nested.y, 2.0); 747 try std.testing.expectEqual(nested_vec3.nested.z, 3.0); 748 749 var nested_vec3_o: NestedVec3 = undefined; 750 const nested_vec3_o_ptr: *NestedVec3 = &nested_vec3_o; 751 nested_vec3_o_ptr.* = nested_vec3; 752 753 try std.testing.expectEqual(nested_vec3_o.nested.x, 1.0); 754 try std.testing.expectEqual(nested_vec3_o.nested.y, 2.0); 755 try std.testing.expectEqual(nested_vec3_o.nested.z, 3.0); 756 757 const hld = packed struct { 758 c: u64, 759 d: u32, 760 }; 761 762 const mld = packed struct { 763 h: u64, 764 i: u64, 765 }; 766 767 const a = packed struct { 768 b: hld, 769 g: mld, 770 }; 771 772 var arg = a{ .b = hld{ .c = 1, .d = 2 }, .g = mld{ .h = 6, .i = 8 } }; 773 try std.testing.expect(arg.b.c == 1); 774 try std.testing.expect(arg.b.d == 2); 775 try std.testing.expect(arg.g.h == 6); 776 try std.testing.expect(arg.g.i == 8); 777 } 778 779 test "nested packed struct at non-zero offset" { 780 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 781 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 782 783 const Pair = packed struct(u24) { 784 a: u16 = 0, 785 b: u8 = 0, 786 }; 787 const A = packed struct { 788 p1: Pair, 789 p2: Pair, 790 }; 791 792 var k: u8 = 123; 793 var v: A = .{ 794 .p1 = .{ .a = k + 1, .b = k }, 795 .p2 = .{ .a = k + 1, .b = k }, 796 }; 797 798 try expect(v.p1.a == k + 1 and v.p1.b == k); 799 try expect(v.p2.a == k + 1 and v.p2.b == k); 800 801 v.p2.a -= v.p1.a; 802 v.p2.b -= v.p1.b; 803 try expect(v.p2.a == 0 and v.p2.b == 0); 804 try expect(v.p1.a == k + 1 and v.p1.b == k); 805 } 806 807 test "nested packed struct at non-zero offset 2" { 808 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO 809 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 810 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 811 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 812 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 813 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits 814 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; 815 816 const S = struct { 817 const Pair = packed struct(u40) { 818 a: u32 = 0, 819 b: u8 = 0, 820 }; 821 const A = packed struct { 822 p1: Pair, 823 p2: Pair, 824 c: C, 825 }; 826 const C = packed struct { 827 p1: Pair, 828 pad1: u5, 829 p2: Pair, 830 pad2: u3, 831 last: i16, 832 }; 833 834 fn doTheTest() !void { 835 var k: u8 = 123; 836 var v: A = .{ 837 .p1 = .{ .a = k + 1, .b = k }, 838 .p2 = .{ .a = k + 1, .b = k }, 839 .c = .{ 840 .pad1 = 11, 841 .pad2 = 2, 842 .p1 = .{ .a = k + 1, .b = k }, 843 .p2 = .{ .a = k + 1, .b = k }, 844 .last = -12345, 845 }, 846 }; 847 848 try expect(v.p1.a == k + 1 and v.p1.b == k); 849 try expect(v.p2.a == k + 1 and v.p2.b == k); 850 try expect(v.c.p2.a == k + 1 and v.c.p2.b == k); 851 try expect(v.c.p2.a == k + 1 and v.c.p2.b == k); 852 try expect(v.c.last == -12345); 853 try expect(v.c.pad1 == 11 and v.c.pad2 == 2); 854 855 v.p2.a -= v.p1.a; 856 v.p2.b -= v.p1.b; 857 v.c.p2.a -= v.c.p1.a; 858 v.c.p2.b -= v.c.p1.b; 859 v.c.last -|= 32000; 860 try expect(v.p2.a == 0 and v.p2.b == 0); 861 try expect(v.p1.a == k + 1 and v.p1.b == k); 862 try expect(v.c.p2.a == 0 and v.c.p2.b == 0); 863 try expect(v.c.p1.a == k + 1 and v.c.p1.b == k); 864 try expect(v.c.last == -32768); 865 try expect(v.c.pad1 == 11 and v.c.pad2 == 2); 866 } 867 }; 868 869 try S.doTheTest(); 870 try comptime S.doTheTest(); 871 } 872 873 test "runtime init of unnamed packed struct type" { 874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 875 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 876 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 877 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 878 879 var z: u8 = 123; 880 try (packed struct { 881 x: u8, 882 pub fn m(s: @This()) !void { 883 try expect(s.x == 123); 884 } 885 }{ .x = z }).m(); 886 } 887 888 test "packed struct passed to callconv(.C) function" { 889 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 890 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 891 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 892 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 893 894 const S = struct { 895 const Packed = packed struct { 896 a: u16, 897 b: bool = true, 898 c: bool = true, 899 d: u46 = 0, 900 }; 901 902 fn foo(p: Packed, a1: u64, a2: u64, a3: u64, a4: u64, a5: u64) callconv(.C) bool { 903 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; 904 } 905 }; 906 const result = S.foo(S.Packed{ 907 .a = 12345, 908 .b = true, 909 .c = true, 910 }, 5, 4, 3, 2, 1); 911 try expect(result); 912 } 913 914 test "overaligned pointer to packed struct" { 915 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 916 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 917 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 918 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 919 920 const S = packed struct { a: u32, b: u32 }; 921 var foo: S align(4) = .{ .a = 123, .b = 456 }; 922 const ptr: *align(4) S = &foo; 923 switch (comptime builtin.cpu.arch.endian()) { 924 .little => { 925 const ptr_to_b: *u32 = &ptr.b; 926 try expect(ptr_to_b.* == 456); 927 }, 928 .big => { 929 // Byte aligned packed struct field pointers have not been implemented yet. 930 const ptr_to_a: *align(4:0:8) u32 = &ptr.a; 931 try expect(ptr_to_a.* == 123); 932 }, 933 } 934 } 935 936 test "packed struct initialized in bitcast" { 937 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO 938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO 939 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 940 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 941 942 const T = packed struct { val: u8 }; 943 var val: u8 = 123; 944 const t = @as(u8, @bitCast(T{ .val = val })); 945 try expect(t == val); 946 } 947 948 test "pointer to container level packed struct field" { 949 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 950 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 951 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 952 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 953 954 const S = packed struct(u32) { 955 test_bit: bool, 956 someother_data: u12, 957 other_test_bit: bool, 958 someother_more_different_data: u12, 959 other_bits: packed struct(u6) { 960 enable_1: bool, 961 enable_2: bool, 962 enable_3: bool, 963 enable_4: bool, 964 enable_5: bool, 965 enable_6: bool, 966 }, 967 var arr = [_]u32{0} ** 2; 968 }; 969 @as(*S, @ptrCast(&S.arr[0])).other_bits.enable_3 = true; 970 try expect(S.arr[0] == 0x10000000); 971 } 972 973 test "store undefined to packed result location" { 974 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 975 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 976 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 977 978 var x: u4 = 0; 979 var s = packed struct { x: u4, y: u4 }{ .x = x, .y = if (x > 0) x else undefined }; 980 try expectEqual(x, s.x); 981 } 982 983 test "bitcast back and forth" { 984 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 985 986 // Originally reported at https://github.com/ziglang/zig/issues/9914 987 const S = packed struct { one: u6, two: u1 }; 988 const s = S{ .one = 0b110101, .two = 0b1 }; 989 const u: u7 = @bitCast(s); 990 const s2: S = @bitCast(u); 991 try expect(s.one == s2.one); 992 try expect(s.two == s2.two); 993 } 994 995 test "field access of packed struct smaller than its abi size inside struct initialized with rls" { 996 // Originally reported at https://github.com/ziglang/zig/issues/14200 997 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 998 999 const S = struct { 1000 ps: packed struct { x: i2, y: i2 }, 1001 1002 fn init(cond: bool) @This() { 1003 return .{ .ps = .{ .x = 0, .y = if (cond) 1 else 0 } }; 1004 } 1005 }; 1006 1007 var s = S.init(true); 1008 // note: this bug is triggered by the == operator, expectEqual will hide it 1009 try expect(@as(i2, 0) == s.ps.x); 1010 try expect(@as(i2, 1) == s.ps.y); 1011 } 1012 1013 test "modify nested packed struct aligned field" { 1014 // Originally reported at https://github.com/ziglang/zig/issues/14632 1015 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 1016 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; 1017 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; 1018 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 1019 1020 const Options = packed struct { 1021 foo: bool = false, 1022 bar: bool = false, 1023 pretty_print: packed struct { 1024 enabled: bool = false, 1025 num_spaces: u4 = 4, 1026 space_char: enum { space, tab } = .space, 1027 indent: u8 = 0, 1028 } = .{}, 1029 baz: bool = false, 1030 }; 1031 1032 var opts = Options{}; 1033 opts.pretty_print.indent += 1; 1034 try std.testing.expectEqual(@as(u17, 0b00000000100100000), @bitCast(opts)); 1035 try std.testing.expect(!opts.foo); 1036 try std.testing.expect(!opts.bar); 1037 try std.testing.expect(!opts.pretty_print.enabled); 1038 try std.testing.expectEqual(@as(u4, 4), opts.pretty_print.num_spaces); 1039 try std.testing.expectEqual(@as(u8, 1), opts.pretty_print.indent); 1040 try std.testing.expect(!opts.baz); 1041 } 1042 1043 test "assigning packed struct inside another packed struct" { 1044 // Originally reported at https://github.com/ziglang/zig/issues/9674 1045 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; 1046 1047 const S = struct { 1048 const Inner = packed struct { 1049 bits: u3, 1050 more_bits: u6, 1051 }; 1052 1053 const Outer = packed struct { 1054 padding: u5, 1055 inner: Inner, 1056 }; 1057 fn t(inner: Inner) void { 1058 r.inner = inner; 1059 } 1060 1061 var mem: Outer = undefined; 1062 var r: *volatile Outer = &mem; 1063 }; 1064 1065 const val = S.Inner{ .bits = 1, .more_bits = 11 }; 1066 S.mem.padding = 0; 1067 S.t(val); 1068 1069 try expectEqual(val, S.mem.inner); 1070 try expect(S.mem.padding == 0); 1071 }