| author | |
| committer | |
| log | 2fcac141e75598dc0edd357b55c35d468b506672 |
| tree | bdda10f0253587ba97ef9e8673f59fae7fd53e70 |
| parent | 2e0524954405e05d8b2bfa4a15c293f26a4a080d |
| signature |
16 files changed, 253 insertions(+), 285 deletions(-)
doc/langref/test_packed_structs.zig+2-10| ... | @@ -26,16 +26,8 @@ fn doTheTest() !void { | ... | @@ -26,16 +26,8 @@ fn doTheTest() !void { |
| 26 | try expectEqual(0x1, divided.quarter4); | 26 | try expectEqual(0x1, divided.quarter4); |
| 27 | 27 | ||
| 28 | const ordered: [2]u8 = @bitCast(full); | 28 | const ordered: [2]u8 = @bitCast(full); |
| 29 | switch (native_endian) { | 29 | try expectEqual(0x34, ordered[0]); |
| 30 | .big => { | 30 | try expectEqual(0x12, ordered[1]); |
| 31 | try expectEqual(0x12, ordered[0]); | ||
| 32 | try expectEqual(0x34, ordered[1]); | ||
| 33 | }, | ||
| 34 | .little => { | ||
| 35 | try expectEqual(0x34, ordered[0]); | ||
| 36 | try expectEqual(0x12, ordered[1]); | ||
| 37 | }, | ||
| 38 | } | ||
| 39 | } | 31 | } |
| 40 | 32 | ||
| 41 | // test | 33 | // test |
doc/langref/test_pointer_casting.zig+12-8| ... | @@ -1,18 +1,22 @@ | ... | @@ -1,18 +1,22 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const native_endian = @import("builtin").target.cpu.arch.endian(); | ||
| 2 | const expectEqual = std.testing.expectEqual; | 3 | const expectEqual = std.testing.expectEqual; |
| 3 | 4 | ||
| 4 | test "pointer casting" { | 5 | test "pointer casting" { |
| 5 | const bytes align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12 }; | 6 | const bytes: [4]u8 align(@alignOf(u32)) = .{ 0x10, 0x20, 0x30, 0x40 }; |
| 6 | const u32_ptr: *const u32 = @ptrCast(&bytes); | 7 | const u32_ptr: *const u32 = @ptrCast(&bytes); |
| 7 | try expectEqual(0x12121212, u32_ptr.*); | ||
| 8 | 8 | ||
| 9 | // Even this example is contrived - there are better ways to do the above than | 9 | // Because we directly reinterpreted bytes of memory, the `u32` value we |
| 10 | // pointer casting. For example, using a slice narrowing cast: | 10 | // load from `u32_ptr` depends on the target endian: |
| 11 | const u32_value = std.mem.bytesAsSlice(u32, bytes[0..])[0]; | 11 | switch (native_endian) { |
| 12 | try expectEqual(0x12121212, u32_value); | 12 | .little => try expectEqual(0x40302010, u32_ptr.*), |
| 13 | .big => try expectEqual(0x10203040, u32_ptr.*), | ||
| 14 | } | ||
| 13 | 15 | ||
| 14 | // And even another way, the most straightforward way to do it: | 16 | // To instead reinterpret the logical bit representation of `bytes` with no |
| 15 | try expectEqual(0x12121212, @as(u32, @bitCast(bytes))); | 17 | // dependency on the target endian, use `@bitCast`, which always places |
| 18 | // earlier array elements into less-significant bits: | ||
| 19 | try expectEqual(0x40302010, @as(u32, @bitCast(bytes))); | ||
| 16 | } | 20 | } |
| 17 | 21 | ||
| 18 | test "pointer child type" { | 22 | test "pointer child type" { |
test/behavior/asm.zig-36| ... | @@ -209,42 +209,6 @@ test "packed output types (x86_64)" { | ... | @@ -209,42 +209,6 @@ test "packed output types (x86_64)" { |
| 209 | } | 209 | } |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | test "extern output types (x86_64)" { | ||
| 213 | if (builtin.target.cpu.arch != .x86_64) return error.SkipZigTest; | ||
| 214 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly | ||
| 215 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/31531 | ||
| 216 | |||
| 217 | const S = extern struct { x: u32 }; | ||
| 218 | { | ||
| 219 | const s: S = asm volatile ("mov $123, %[ret]" | ||
| 220 | : [ret] "=r" (-> S), | ||
| 221 | ); | ||
| 222 | try expect(s.x == 123); | ||
| 223 | } | ||
| 224 | { | ||
| 225 | var s: S = undefined; | ||
| 226 | asm volatile ("mov $123, %[ret]" | ||
| 227 | : [ret] "=r" (s), | ||
| 228 | ); | ||
| 229 | try expect(s.x == 123); | ||
| 230 | } | ||
| 231 | |||
| 232 | const U = extern union { x: u32 }; | ||
| 233 | { | ||
| 234 | const u: U = asm volatile ("mov $123, %[ret]" | ||
| 235 | : [ret] "=r" (-> U), | ||
| 236 | ); | ||
| 237 | try expect(u.x == 123); | ||
| 238 | } | ||
| 239 | { | ||
| 240 | var u: U = undefined; | ||
| 241 | asm volatile ("mov $123, %[ret]" | ||
| 242 | : [ret] "=r" (u), | ||
| 243 | ); | ||
| 244 | try expect(u.x == 123); | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | test "abi register aliases as clobbers (RISC-V)" { | 212 | test "abi register aliases as clobbers (RISC-V)" { |
| 249 | if (!builtin.target.cpu.arch.isRISCV()) return error.SkipZigTest; | 213 | if (!builtin.target.cpu.arch.isRISCV()) return error.SkipZigTest; |
| 250 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 214 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/atomics.zig-1| ... | @@ -358,7 +358,6 @@ test "atomics with different types" { | ... | @@ -358,7 +358,6 @@ test "atomics with different types" { |
| 358 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 358 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 359 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 359 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 360 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 360 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 361 | if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // #24282 | ||
| 362 | 361 | ||
| 363 | try testAtomicsWithType(bool, true, false); | 362 | try testAtomicsWithType(bool, true, false); |
| 364 | 363 |
test/behavior/bitcast.zig+141-167| ... | @@ -74,55 +74,6 @@ fn conv_uN(comptime N: usize, x: @Int(.unsigned, N)) @Int(.signed, N) { | ... | @@ -74,55 +74,6 @@ fn conv_uN(comptime N: usize, x: @Int(.unsigned, N)) @Int(.signed, N) { |
| 74 | return @as(@Int(.signed, N), @bitCast(x)); | 74 | return @as(@Int(.signed, N), @bitCast(x)); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | test "bitcast uX to bytes" { | ||
| 78 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 79 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 80 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 81 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 82 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 83 | |||
| 84 | const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 }; | ||
| 85 | inline for (bit_values) |bits| { | ||
| 86 | try testBitCast(bits); | ||
| 87 | try comptime testBitCast(bits); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | fn testBitCastuXToBytes(comptime N: usize) !void { | ||
| 92 | |||
| 93 | // The location of padding bits in these layouts are technically not defined | ||
| 94 | // by LLVM, but we currently allow exotic integers to be cast (at comptime) | ||
| 95 | // to types that expose their padding bits anyway. | ||
| 96 | // | ||
| 97 | // This test at least makes sure those bits are matched by the runtime behavior | ||
| 98 | // on the platforms we target. If the above behavior is restricted after all, | ||
| 99 | // this test should be deleted. | ||
| 100 | |||
| 101 | const T = @Int(.unsigned, N); | ||
| 102 | for ([_]T{ 0, ~@as(T, 0) }) |init_value| { | ||
| 103 | var x: T = init_value; | ||
| 104 | const bytes = std.mem.asBytes(&x); | ||
| 105 | |||
| 106 | const byte_count = (N + 7) / 8; | ||
| 107 | switch (native_endian) { | ||
| 108 | .little => { | ||
| 109 | var byte_i = 0; | ||
| 110 | while (byte_i < (byte_count - 1)) : (byte_i += 1) { | ||
| 111 | try expect(bytes[byte_i] == 0xff); | ||
| 112 | } | ||
| 113 | try expect(((bytes[byte_i] ^ 0xff) << -%@as(u3, @truncate(N))) == 0); | ||
| 114 | }, | ||
| 115 | .big => { | ||
| 116 | var byte_i = byte_count - 1; | ||
| 117 | while (byte_i > 0) : (byte_i -= 1) { | ||
| 118 | try expect(bytes[byte_i] == 0xff); | ||
| 119 | } | ||
| 120 | try expect(((bytes[byte_i] ^ 0xff) << -%@as(u3, @truncate(N))) == 0); | ||
| 121 | }, | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | test "nested bitcast" { | 77 | test "nested bitcast" { |
| 127 | const S = struct { | 78 | const S = struct { |
| 128 | fn moo(x: isize) !void { | 79 | fn moo(x: isize) !void { |
| ... | @@ -183,39 +134,6 @@ test "@bitCast packed structs at runtime and comptime" { | ... | @@ -183,39 +134,6 @@ test "@bitCast packed structs at runtime and comptime" { |
| 183 | try comptime S.doTheTest(); | 134 | try comptime S.doTheTest(); |
| 184 | } | 135 | } |
| 185 | 136 | ||
| 186 | test "@bitCast extern structs at runtime and comptime" { | ||
| 187 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 188 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 189 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 190 | |||
| 191 | const Full = extern struct { | ||
| 192 | number: u16, | ||
| 193 | }; | ||
| 194 | const TwoHalves = extern struct { | ||
| 195 | half1: u8, | ||
| 196 | half2: u8, | ||
| 197 | }; | ||
| 198 | const S = struct { | ||
| 199 | fn doTheTest() !void { | ||
| 200 | var full = Full{ .number = 0x1234 }; | ||
| 201 | _ = &full; | ||
| 202 | const two_halves: TwoHalves = @bitCast(full); | ||
| 203 | switch (native_endian) { | ||
| 204 | .big => { | ||
| 205 | try expect(two_halves.half1 == 0x12); | ||
| 206 | try expect(two_halves.half2 == 0x34); | ||
| 207 | }, | ||
| 208 | .little => { | ||
| 209 | try expect(two_halves.half1 == 0x34); | ||
| 210 | try expect(two_halves.half2 == 0x12); | ||
| 211 | }, | ||
| 212 | } | ||
| 213 | } | ||
| 214 | }; | ||
| 215 | try S.doTheTest(); | ||
| 216 | try comptime S.doTheTest(); | ||
| 217 | } | ||
| 218 | |||
| 219 | test "bitcast packed struct to integer and back" { | 137 | test "bitcast packed struct to integer and back" { |
| 220 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 138 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 221 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 139 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| ... | @@ -363,32 +281,12 @@ test "comptime @bitCast packed struct to int and back" { | ... | @@ -363,32 +281,12 @@ test "comptime @bitCast packed struct to int and back" { |
| 363 | } | 281 | } |
| 364 | } | 282 | } |
| 365 | 283 | ||
| 366 | test "comptime bitcast with fields following f80" { | ||
| 367 | if (true) { | ||
| 368 | // https://github.com/ziglang/zig/issues/19387 | ||
| 369 | return error.SkipZigTest; | ||
| 370 | } | ||
| 371 | |||
| 372 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | ||
| 373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 374 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 375 | |||
| 376 | const FloatT = extern struct { f: f80, x: u128 align(16) }; | ||
| 377 | const x: FloatT = .{ .f = 0.5, .x = 123 }; | ||
| 378 | var x_as_uint: u256 = comptime @as(u256, @bitCast(x)); | ||
| 379 | _ = &x_as_uint; | ||
| 380 | |||
| 381 | try expect(x.f == @as(FloatT, @bitCast(x_as_uint)).f); | ||
| 382 | try expect(x.x == @as(FloatT, @bitCast(x_as_uint)).x); | ||
| 383 | } | ||
| 384 | |||
| 385 | test "bitcast vector to integer and back" { | 284 | test "bitcast vector to integer and back" { |
| 386 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 285 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 387 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 286 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 388 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 287 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 389 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 288 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 390 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 289 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 391 | if (builtin.cpu.arch.endian() == .big and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; | ||
| 392 | 290 | ||
| 393 | var vec: @Vector(16, bool) = @splat(true); | 291 | var vec: @Vector(16, bool) = @splat(true); |
| 394 | vec[1] = false; | 292 | vec[1] = false; |
| ... | @@ -524,87 +422,163 @@ test "@bitCast of packed struct of bools all false" { | ... | @@ -524,87 +422,163 @@ test "@bitCast of packed struct of bools all false" { |
| 524 | try expect(@as(u8, @as(u4, @bitCast(p))) == 0); | 422 | try expect(@as(u8, @as(u4, @bitCast(p))) == 0); |
| 525 | } | 423 | } |
| 526 | 424 | ||
| 527 | test "@bitCast of extern struct containing pointer" { | 425 | test "@bitCast of packed struct with void field to integer" { |
| 528 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 426 | const S = packed struct(u8) { |
| 529 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 427 | v: void, |
| 530 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 428 | x: u8, |
| 531 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO | ||
| 532 | |||
| 533 | const S = struct { | ||
| 534 | const A = extern struct { | ||
| 535 | ptr: *const u32, | ||
| 536 | }; | ||
| 537 | |||
| 538 | const B = extern struct { | ||
| 539 | ptr: *const i32, | ||
| 540 | }; | ||
| 541 | 429 | ||
| 542 | fn doTheTest() !void { | 430 | fn doTheTest(x: u8) !void { |
| 543 | const x: u32 = 123; | 431 | // Intentionally using `@as` to avoid RLS which masks the bug |
| 544 | var a: A = undefined; | 432 | const foo = @as(@This(), .{ .v = {}, .x = x }); |
| 545 | a = .{ .ptr = &x }; | 433 | const as_int: u8 = @bitCast(foo); |
| 546 | const b: B = @bitCast(a); | 434 | try expect(as_int == x); |
| 547 | try expect(b.ptr.* == 123); | ||
| 548 | } | 435 | } |
| 549 | }; | 436 | }; |
| 550 | 437 | try S.doTheTest(123); | |
| 551 | try S.doTheTest(); | 438 | try comptime S.doTheTest(123); |
| 552 | try comptime S.doTheTest(); | ||
| 553 | } | 439 | } |
| 554 | 440 | ||
| 555 | test "@bitCast of extern struct to float" { | 441 | test "@bitCast vector to array with different element size" { |
| 556 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 442 | const static = struct { |
| 557 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 443 | fn doTheTest(v: @Vector(4, u5)) !void { |
| 558 | 444 | const result: [5]u4 = @bitCast(v); | |
| 559 | const S = struct { | 445 | // See the definition of `v` in the test proper for these values. |
| 560 | const S = extern struct { | 446 | try expect(result[0] == 0b0010); |
| 561 | x: u16, | 447 | try expect(result[1] == 0b1110); |
| 562 | y: u16, | 448 | try expect(result[2] == 0b0101); |
| 563 | }; | 449 | try expect(result[3] == 0b0110); |
| 564 | fn doTheTest() !void { | 450 | try expect(result[4] == 0b0000); |
| 565 | var s: S = .{ .x = 0, .y = 0 }; | 451 | } |
| 566 | _ = &s; | 452 | }; |
| 567 | const a: f32 = @bitCast(s); | 453 | // The strange digit groupings here are to indicate how this maps to `expected` above. |
| 568 | try expect(a == 0); | 454 | const v: @Vector(4, u5) = .{ |
| 455 | 0b0_0010, | ||
| 456 | 0b01_111, | ||
| 457 | 0b110_01, | ||
| 458 | 0b0000_0, | ||
| 459 | }; | ||
| 460 | try static.doTheTest(v); | ||
| 461 | try comptime static.doTheTest(v); | ||
| 462 | } | ||
| 463 | |||
| 464 | test "@bitCast packed struct to array of bits" { | ||
| 465 | const S = packed struct(u16) { | ||
| 466 | foo: u5, | ||
| 467 | bar: i7, | ||
| 468 | baz: u3, | ||
| 469 | qux: bool, | ||
| 470 | fn doTheTest(val: @This(), comptime Bits: type) !void { | ||
| 471 | const bits: Bits = @bitCast(val); | ||
| 472 | |||
| 473 | // foo | ||
| 474 | try expect(bits[0] == 1); | ||
| 475 | try expect(bits[1] == 0); | ||
| 476 | try expect(bits[2] == 0); | ||
| 477 | try expect(bits[3] == 1); | ||
| 478 | try expect(bits[4] == 0); | ||
| 479 | // bar | ||
| 480 | try expect(bits[5] == 0); | ||
| 481 | try expect(bits[6] == 1); | ||
| 482 | try expect(bits[7] == 1); | ||
| 483 | try expect(bits[8] == 1); | ||
| 484 | try expect(bits[9] == 1); | ||
| 485 | try expect(bits[10] == 1); | ||
| 486 | try expect(bits[11] == 1); | ||
| 487 | // baz | ||
| 488 | try expect(bits[12] == 0); | ||
| 489 | try expect(bits[13] == 1); | ||
| 490 | try expect(bits[14] == 0); | ||
| 491 | // qux | ||
| 492 | try expect(bits[15] == 1); | ||
| 569 | } | 493 | } |
| 570 | }; | 494 | }; |
| 571 | 495 | ||
| 572 | try S.doTheTest(); | 496 | const val: S = .{ |
| 573 | try comptime S.doTheTest(); | 497 | .foo = 0b01001, |
| 498 | .bar = -2, | ||
| 499 | .baz = 0b010, | ||
| 500 | .qux = true, | ||
| 501 | }; | ||
| 502 | |||
| 503 | try val.doTheTest(@Vector(16, u1)); | ||
| 504 | try val.doTheTest([16]u1); | ||
| 505 | |||
| 506 | try comptime val.doTheTest(@Vector(16, u1)); | ||
| 507 | try comptime val.doTheTest([16]u1); | ||
| 574 | } | 508 | } |
| 575 | 509 | ||
| 576 | test "@bitCast of float to extern struct" { | 510 | test "@bitCast nested arrays of vectors" { |
| 577 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 511 | const Src = [2][2]@Vector(4, u5); |
| 578 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 512 | const Dest = [5]@Vector(2, u8); |
| 579 | 513 | ||
| 580 | const S = struct { | 514 | // The strange digit groupings here are to indicate how this maps to the output. |
| 581 | const S = extern struct { | 515 | const src: Src = .{ .{ |
| 582 | x: u32, | 516 | .{ 0b00011, 0b00_100, 0b11100, 0b0010_1 }, |
| 583 | }; | 517 | .{ 0b1_0110, 0b11011, 0b101_10, 0b10101 }, |
| 584 | fn doTheTest() !void { | 518 | }, .{ |
| 585 | var a: f32 = -0.0; | 519 | .{ 0b10101, 0b00_001, 0b01011, 0b0001_0 }, |
| 586 | _ = &a; | 520 | .{ 0b0_0001, 0b01111, 0b111_10, 0b00001 }, |
| 587 | const s: S = @bitCast(a); | 521 | } }; |
| 588 | try expect(s.x == 0x80000000); | 522 | |
| 523 | const expected: Dest = .{ | ||
| 524 | .{ 0b10000011, 0b11110000 }, | ||
| 525 | .{ 0b01100010, 0b10110111 }, | ||
| 526 | .{ 0b10101101, 0b00110101 }, | ||
| 527 | .{ 0b00101100, 0b00010001 }, | ||
| 528 | .{ 0b10011110, 0b00001111 }, | ||
| 529 | }; | ||
| 530 | |||
| 531 | const static = struct { | ||
| 532 | fn doTheTest(src_arg: Src) !void { | ||
| 533 | const actual: Dest = @bitCast(src_arg); | ||
| 534 | for (actual, expected) |actual_vec, expected_vec| { | ||
| 535 | try expect(actual_vec[0] == expected_vec[0]); | ||
| 536 | try expect(actual_vec[1] == expected_vec[1]); | ||
| 537 | } | ||
| 589 | } | 538 | } |
| 590 | }; | 539 | }; |
| 591 | 540 | ||
| 592 | try S.doTheTest(); | 541 | try static.doTheTest(src); |
| 593 | try comptime S.doTheTest(); | 542 | try comptime static.doTheTest(src); |
| 594 | } | 543 | } |
| 595 | 544 | ||
| 596 | test "@bitCast of packed struct with void field to integer" { | 545 | test "@bitCast nested arrays of bool to scalar" { |
| 597 | const S = packed struct(u8) { | 546 | const static = struct { |
| 598 | v: void, | 547 | fn doTheTest(src: [4][4]bool) !void { |
| 599 | x: u8, | 548 | const result: u16 = @bitCast(src); |
| 600 | 549 | try expect(result == 0b1100_0101_1010_0011); | |
| 601 | fn doTheTest(x: u8) !void { | ||
| 602 | // Intentionally using `@as` to avoid RLS which masks the bug | ||
| 603 | const foo = @as(@This(), .{ .v = {}, .x = x }); | ||
| 604 | const as_int: u8 = @bitCast(foo); | ||
| 605 | try expect(as_int == x); | ||
| 606 | } | 550 | } |
| 607 | }; | 551 | }; |
| 608 | try S.doTheTest(123); | 552 | const src: [4][4]bool = .{ |
| 609 | try comptime S.doTheTest(123); | 553 | .{ true, true, false, false }, // 0b0011 |
| 554 | .{ false, true, false, true }, // 0b1010 | ||
| 555 | .{ true, false, true, false }, // 0b0101 | ||
| 556 | .{ false, false, true, true }, // 0b1100 | ||
| 557 | }; | ||
| 558 | try static.doTheTest(src); | ||
| 559 | try comptime static.doTheTest(src); | ||
| 560 | } | ||
| 561 | |||
| 562 | test "@bitCast deeply nested arrays to scalar" { | ||
| 563 | const static = struct { | ||
| 564 | fn doTheTest(src: [2][1][3][5]u4) !void { | ||
| 565 | const signed: i120 = @bitCast(src); | ||
| 566 | try expect(signed < 0); // top nibble is 0x8 so sign bit is 1 | ||
| 567 | const unsigned: u120 = @bitCast(src); | ||
| 568 | try expect(unsigned == 0x8873B_5BF6F_F4020_0E7AC_1EFED_40F51); | ||
| 569 | try expect(@as(i120, @bitCast(unsigned)) == signed); | ||
| 570 | try expect(@as(u120, @bitCast(signed)) == unsigned); | ||
| 571 | } | ||
| 572 | }; | ||
| 573 | const src: [2][1][3][5]u4 = .{ .{.{ | ||
| 574 | .{ 0x1, 0x5, 0xF, 0x0, 0x4 }, | ||
| 575 | .{ 0xD, 0xE, 0xF, 0xE, 0x1 }, | ||
| 576 | .{ 0xC, 0xA, 0x7, 0xE, 0x0 }, | ||
| 577 | }}, .{.{ | ||
| 578 | .{ 0x0, 0x2, 0x0, 0x4, 0xF }, | ||
| 579 | .{ 0xF, 0x6, 0xF, 0xB, 0x5 }, | ||
| 580 | .{ 0xB, 0x3, 0x7, 0x8, 0x8 }, | ||
| 581 | }} }; | ||
| 582 | try static.doTheTest(src); | ||
| 583 | try comptime static.doTheTest(src); | ||
| 610 | } | 584 | } |
test/behavior/comptime_memory.zig+16| ... | @@ -583,3 +583,19 @@ test "comptime store to extern struct reinterpreted as byte array" { | ... | @@ -583,3 +583,19 @@ test "comptime store to extern struct reinterpreted as byte array" { |
| 583 | 583 | ||
| 584 | comptime std.debug.assert(val.x == 0); | 584 | comptime std.debug.assert(val.x == 0); |
| 585 | } | 585 | } |
| 586 | |||
| 587 | test "reinterpret sentinel-terminated array as packed struct" { | ||
| 588 | const S = packed struct(u16) { lo: u8, hi: u8 }; | ||
| 589 | const data: [2:0]u8 = .{ 0x12, 0x34 }; | ||
| 590 | const ptr: *align(1) const S = @ptrCast(&data); | ||
| 591 | switch (endian) { | ||
| 592 | .little => { | ||
| 593 | try testing.expect(ptr.lo == 0x12); | ||
| 594 | try testing.expect(ptr.hi == 0x34); | ||
| 595 | }, | ||
| 596 | .big => { | ||
| 597 | try testing.expect(ptr.lo == 0x34); | ||
| 598 | try testing.expect(ptr.hi == 0x12); | ||
| 599 | }, | ||
| 600 | } | ||
| 601 | } |
test/behavior/sizeof_and_typeof.zig-11| ... | @@ -151,9 +151,6 @@ test "branching logic inside @TypeOf" { | ... | @@ -151,9 +151,6 @@ test "branching logic inside @TypeOf" { |
| 151 | test "@bitSizeOf" { | 151 | test "@bitSizeOf" { |
| 152 | try expect(@bitSizeOf(u2) == 2); | 152 | try expect(@bitSizeOf(u2) == 2); |
| 153 | try expect(@bitSizeOf(u8) == @sizeOf(u8) * 8); | 153 | try expect(@bitSizeOf(u8) == @sizeOf(u8) * 8); |
| 154 | try expect(@bitSizeOf(struct { | ||
| 155 | a: u2, | ||
| 156 | }) == 8); | ||
| 157 | try expect(@bitSizeOf(packed struct { | 154 | try expect(@bitSizeOf(packed struct { |
| 158 | a: u2, | 155 | a: u2, |
| 159 | }) == 2); | 156 | }) == 2); |
| ... | @@ -281,14 +278,6 @@ test "@offsetOf zero-bit field" { | ... | @@ -281,14 +278,6 @@ test "@offsetOf zero-bit field" { |
| 281 | try expect(@offsetOf(S, "b") == @offsetOf(S, "c")); | 278 | try expect(@offsetOf(S, "b") == @offsetOf(S, "c")); |
| 282 | } | 279 | } |
| 283 | 280 | ||
| 284 | test "@bitSizeOf on array of structs" { | ||
| 285 | const S = struct { | ||
| 286 | foo: u64, | ||
| 287 | }; | ||
| 288 | |||
| 289 | try expectEqual(128, @bitSizeOf([2]S)); | ||
| 290 | } | ||
| 291 | |||
| 292 | test "lazy abi size used in comparison" { | 281 | test "lazy abi size used in comparison" { |
| 293 | const S = struct { a: usize }; | 282 | const S = struct { a: usize }; |
| 294 | var rhs: i32 = 100; | 283 | var rhs: i32 = 100; |
test/behavior/vector.zig+2-2| ... | @@ -1536,12 +1536,12 @@ test "vector pointer is indexable" { | ... | @@ -1536,12 +1536,12 @@ test "vector pointer is indexable" { |
| 1536 | const V = @Vector(2, u32); | 1536 | const V = @Vector(2, u32); |
| 1537 | 1537 | ||
| 1538 | const x: V = .{ 123, 456 }; | 1538 | const x: V = .{ 123, 456 }; |
| 1539 | comptime assert(@TypeOf(&(&x)[0]) == *const u32); // validate constness | 1539 | comptime assert(@typeInfo(@TypeOf(&(&x)[0])).pointer.attrs.@"const"); |
| 1540 | try expectEqual(@as(u32, 123), (&x)[0]); | 1540 | try expectEqual(@as(u32, 123), (&x)[0]); |
| 1541 | try expectEqual(@as(u32, 456), (&x)[1]); | 1541 | try expectEqual(@as(u32, 456), (&x)[1]); |
| 1542 | 1542 | ||
| 1543 | var y: V = .{ 123, 456 }; | 1543 | var y: V = .{ 123, 456 }; |
| 1544 | comptime assert(@TypeOf(&(&y)[0]) == *u32); // validate constness | 1544 | comptime assert(!@typeInfo(@TypeOf(&(&y)[0])).pointer.attrs.@"const"); |
| 1545 | try expectEqual(@as(u32, 123), (&y)[0]); | 1545 | try expectEqual(@as(u32, 123), (&y)[0]); |
| 1546 | try expectEqual(@as(u32, 456), (&y)[1]); | 1546 | try expectEqual(@as(u32, 456), (&y)[1]); |
| 1547 | 1547 |
test/c_abi/main.zig+2-1| ... | @@ -17109,7 +17109,8 @@ const byval_tail_callsite_attr = struct { | ... | @@ -17109,7 +17109,8 @@ const byval_tail_callsite_attr = struct { |
| 17109 | } | 17109 | } |
| 17110 | 17110 | ||
| 17111 | fn cast(self: MyRect) struct_Rect { | 17111 | fn cast(self: MyRect) struct_Rect { |
| 17112 | return @bitCast(self); | 17112 | const ptr: *const struct_Rect = @ptrCast(&self); |
| 17113 | return ptr.*; | ||
| 17113 | } | 17114 | } |
| 17114 | 17115 | ||
| 17115 | extern fn c_byval_tail_callsite_attr(struct_Rect) f64; | 17116 | extern fn c_byval_tail_callsite_attr(struct_Rect) f64; |
test/cases/compile_errors/asm_output_type_no_guaranteed_in_memory_layout.zig+28-4| ... | @@ -25,14 +25,38 @@ export fn entry4() void { | ... | @@ -25,14 +25,38 @@ export fn entry4() void { |
| 25 | : [_] "=r" (u), | 25 | : [_] "=r" (u), |
| 26 | ); | 26 | ); |
| 27 | } | 27 | } |
| 28 | const ES = extern struct { x: u32 }; | ||
| 29 | export fn entry5() void { | ||
| 30 | var es: ES = undefined; | ||
| 31 | asm volatile ("" | ||
| 32 | : [_] "=r" (es), | ||
| 33 | ); | ||
| 34 | } | ||
| 35 | const EU = extern union { x: u32 }; | ||
| 36 | export fn entry6() void { | ||
| 37 | var eu: EU = undefined; | ||
| 38 | asm volatile ("" | ||
| 39 | : [_] "=r" (eu), | ||
| 40 | ); | ||
| 41 | } | ||
| 28 | 42 | ||
| 29 | // error | 43 | // error |
| 30 | // | 44 | // |
| 31 | // :4:24: error: invalid inline assembly output type; 'tmp.S' does not have a guaranteed in-memory layout | 45 | // :4:24: error: invalid inline assembly output type 'tmp.S' |
| 46 | // :4:24: note: struct types cannot be passed to inline assembly | ||
| 32 | // :1:11: note: struct declared here | 47 | // :1:11: note: struct declared here |
| 33 | // :11:21: error: invalid inline assembly output type; 'tmp.S' does not have a guaranteed in-memory layout | 48 | // :11:21: error: invalid inline assembly output type 'tmp.S' |
| 49 | // :11:21: note: struct types cannot be passed to inline assembly | ||
| 34 | // :1:11: note: struct declared here | 50 | // :1:11: note: struct declared here |
| 35 | // :18:24: error: invalid inline assembly output type; 'tmp.U' does not have a guaranteed in-memory layout | 51 | // :18:24: error: invalid inline assembly output type 'tmp.U' |
| 52 | // :18:24: note: union types cannot be passed to inline assembly | ||
| 36 | // :15:11: note: union declared here | 53 | // :15:11: note: union declared here |
| 37 | // :25:21: error: invalid inline assembly output type; 'tmp.U' does not have a guaranteed in-memory layout | 54 | // :25:21: error: invalid inline assembly output type 'tmp.U' |
| 55 | // :25:21: note: union types cannot be passed to inline assembly | ||
| 38 | // :15:11: note: union declared here | 56 | // :15:11: note: union declared here |
| 57 | // :32:21: error: invalid inline assembly output type 'tmp.ES' | ||
| 58 | // :32:21: note: struct types cannot be passed to inline assembly | ||
| 59 | // :28:19: note: struct declared here | ||
| 60 | // :39:21: error: invalid inline assembly output type 'tmp.EU' | ||
| 61 | // :39:21: note: union types cannot be passed to inline assembly | ||
| 62 | // :35:19: note: union declared here |
test/cases/compile_errors/bitCast_extern_struct.zig created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | const S = extern struct { x: u32 }; | ||
| 2 | export fn foo(s: S) void { | ||
| 3 | const as_int: u32 = @bitCast(s); | ||
| 4 | _ = as_int; | ||
| 5 | } | ||
| 6 | |||
| 7 | // error | ||
| 8 | // | ||
| 9 | // :3:34: error: cannot @bitCast from 'tmp.S' | ||
| 10 | // :1:18: note: struct declared here | ||
test/cases/compile_errors/bitCast_to_enum_type.zig deleted-10| ... | @@ -1,10 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | const E = enum(u32) { a, b }; | ||
| 3 | const y: E = @bitCast(@as(u32, 3)); | ||
| 4 | _ = y; | ||
| 5 | } | ||
| 6 | |||
| 7 | // error | ||
| 8 | // | ||
| 9 | // :3:18: error: cannot @bitCast to 'tmp.entry.E' | ||
| 10 | // :3:18: note: use @enumFromInt to cast from 'u32' | ||
test/cases/compile_errors/bitCast_vector_of_pointer.zig created+9| ... | @@ -0,0 +1,9 @@ | ||
| 1 | export fn foo(p: *u32) void { | ||
| 2 | const vec: @Vector(2, *u32) = .{ p, p }; | ||
| 3 | const raw: [2]usize = @bitCast(vec); | ||
| 4 | _ = raw; | ||
| 5 | } | ||
| 6 | |||
| 7 | // error | ||
| 8 | // | ||
| 9 | // :3:36: error: cannot @bitCast from '@Vector(2, *u32)' | ||
test/cases/compile_errors/bitCast_with_invalid_array_element_type.zig+2-5| ... | @@ -18,9 +18,6 @@ export fn baz() void { | ... | @@ -18,9 +18,6 @@ export fn baz() void { |
| 18 | 18 | ||
| 19 | // error | 19 | // error |
| 20 | // | 20 | // |
| 21 | // :5:29: error: cannot @bitCast from '[1]tmp.foo.S' | 21 | // :5:42: error: cannot @bitCast from '[1]tmp.foo.S' |
| 22 | // :5:29: note: array element type 'tmp.foo.S' does not have a guaranteed in-memory layout | ||
| 23 | // :12:19: error: cannot @bitCast to '[1]tmp.bar.S' | 22 | // :12:19: error: cannot @bitCast to '[1]tmp.bar.S' |
| 24 | // :12:19: note: array element type 'tmp.bar.S' does not have a guaranteed in-memory layout | 23 | // :16:45: error: cannot @bitCast from '[1]comptime_int' |
| 25 | // :16:21: error: cannot @bitCast from '[1]comptime_int' | ||
| 26 | // :16:21: note: array element type 'comptime_int' does not have a guaranteed in-memory layout |
test/cases/compile_errors/error_in_nested_declaration.zig created+29| ... | @@ -0,0 +1,29 @@ | ||
| 1 | const S = struct { | ||
| 2 | b: u32, | ||
| 3 | c: i32, | ||
| 4 | a: struct { | ||
| 5 | pub fn str(_: @This(), extra: []u32) []i32 { | ||
| 6 | return @bitCast(extra); | ||
| 7 | } | ||
| 8 | }, | ||
| 9 | }; | ||
| 10 | |||
| 11 | pub export fn entry() void { | ||
| 12 | var s: S = undefined; | ||
| 13 | _ = s.a.str(undefined); | ||
| 14 | } | ||
| 15 | |||
| 16 | const S2 = struct { | ||
| 17 | a: [*c]anyopaque, | ||
| 18 | }; | ||
| 19 | |||
| 20 | pub export fn entry2() void { | ||
| 21 | var s: S2 = undefined; | ||
| 22 | _ = &s; | ||
| 23 | } | ||
| 24 | |||
| 25 | // error | ||
| 26 | // | ||
| 27 | // :6:20: error: cannot @bitCast to '[]i32' | ||
| 28 | // :6:20: note: use @ptrCast to cast from '[]u32' | ||
| 29 | // :17:12: error: indexable pointer to opaque type 'anyopaque' not allowed | ||
test/cases/error_in_nested_declaration.zig deleted-30| ... | @@ -1,30 +0,0 @@ | ||
| 1 | const S = struct { | ||
| 2 | b: u32, | ||
| 3 | c: i32, | ||
| 4 | a: struct { | ||
| 5 | pub fn str(_: @This(), extra: []u32) []i32 { | ||
| 6 | return @bitCast(extra); | ||
| 7 | } | ||
| 8 | }, | ||
| 9 | }; | ||
| 10 | |||
| 11 | pub export fn entry() void { | ||
| 12 | var s: S = undefined; | ||
| 13 | _ = s.a.str(undefined); | ||
| 14 | } | ||
| 15 | |||
| 16 | const S2 = struct { | ||
| 17 | a: [*c]anyopaque, | ||
| 18 | }; | ||
| 19 | |||
| 20 | pub export fn entry2() void { | ||
| 21 | var s: S2 = undefined; | ||
| 22 | _ = &s; | ||
| 23 | } | ||
| 24 | |||
| 25 | // error | ||
| 26 | // backend=selfhosted,llvm | ||
| 27 | // | ||
| 28 | // :6:20: error: cannot @bitCast to '[]i32' | ||
| 29 | // :6:20: note: use @ptrCast to cast from '[]u32' | ||
| 30 | // :17:12: error: indexable pointer to opaque type 'anyopaque' not allowed | ||