| author | |
| committer | |
| log | fb33bc99e17427b4dc4143b8c2a5745a9d978db2 |
| tree | e5cbaf8b7af8ddac15eda028892ab02392b76359 |
| parent | d657b6c0e2ab7c47f5416dc4df1abb2bfbecd4b6 |
Updated the tests to also run at runtime, and moved them to union.zig3 files changed, 247 insertions(+), 179 deletions(-)
src/Sema.zig+35-11| ... | @@ -27251,7 +27251,7 @@ fn unionFieldVal( | ... | @@ -27251,7 +27251,7 @@ fn unionFieldVal( |
| 27251 | return sema.failWithOwnedErrorMsg(block, msg); | 27251 | return sema.failWithOwnedErrorMsg(block, msg); |
| 27252 | } | 27252 | } |
| 27253 | }, | 27253 | }, |
| 27254 | .Packed, .Extern => { | 27254 | .Packed, .Extern => |layout| { |
| 27255 | if (tag_matches) { | 27255 | if (tag_matches) { |
| 27256 | return Air.internedToRef(un.val); | 27256 | return Air.internedToRef(un.val); |
| 27257 | } else { | 27257 | } else { |
| ... | @@ -27260,7 +27260,7 @@ fn unionFieldVal( | ... | @@ -27260,7 +27260,7 @@ fn unionFieldVal( |
| 27260 | else | 27260 | else |
| 27261 | union_ty.unionFieldType(un.tag.toValue(), mod).?; | 27261 | union_ty.unionFieldType(un.tag.toValue(), mod).?; |
| 27262 | 27262 | ||
| 27263 | if (try sema.bitCastUnionFieldVal(block, src, un.val.toValue(), old_ty, field_ty)) |new_val| { | 27263 | if (try sema.bitCastUnionFieldVal(block, src, un.val.toValue(), old_ty, field_ty, layout)) |new_val| { |
| 27264 | return Air.internedToRef(new_val.toIntern()); | 27264 | return Air.internedToRef(new_val.toIntern()); |
| 27265 | } | 27265 | } |
| 27266 | } | 27266 | } |
| ... | @@ -30751,26 +30751,50 @@ fn bitCastUnionFieldVal( | ... | @@ -30751,26 +30751,50 @@ fn bitCastUnionFieldVal( |
| 30751 | val: Value, | 30751 | val: Value, |
| 30752 | old_ty: Type, | 30752 | old_ty: Type, |
| 30753 | field_ty: Type, | 30753 | field_ty: Type, |
| 30754 | layout: std.builtin.Type.ContainerLayout, | ||
| 30754 | ) !?Value { | 30755 | ) !?Value { |
| 30755 | const mod = sema.mod; | 30756 | const mod = sema.mod; |
| 30756 | if (old_ty.eql(field_ty, mod)) return val; | 30757 | if (old_ty.eql(field_ty, mod)) return val; |
| 30757 | 30758 | ||
| 30758 | const old_size = try sema.usizeCast(block, src, old_ty.abiSize(mod)); | 30759 | const old_size = try sema.usizeCast(block, src, old_ty.abiSize(mod)); |
| 30759 | const field_size = try sema.usizeCast(block, src, field_ty.abiSize(mod)); | 30760 | const field_size = try sema.usizeCast(block, src, field_ty.abiSize(mod)); |
| 30761 | const endian = mod.getTarget().cpu.arch.endian(); | ||
| 30760 | 30762 | ||
| 30761 | const buffer = try sema.gpa.alloc(u8, @max(old_size, field_size)); | 30763 | const buffer = try sema.gpa.alloc(u8, @max(old_size, field_size)); |
| 30762 | defer sema.gpa.free(buffer); | 30764 | defer sema.gpa.free(buffer); |
| 30763 | val.writeToMemory(old_ty, mod, buffer) catch |err| switch (err) { | ||
| 30764 | error.OutOfMemory => return error.OutOfMemory, | ||
| 30765 | error.ReinterpretDeclRef => return null, | ||
| 30766 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already | ||
| 30767 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(mod)}), | ||
| 30768 | }; | ||
| 30769 | 30765 | ||
| 30770 | // Reading a larger value means we need to reinterpret from undefined bytes | 30766 | // Reading a larger value means we need to reinterpret from undefined bytes. |
| 30771 | if (field_size > old_size) @memset(buffer[old_size..], 0xaa); | 30767 | const offset = switch (layout) { |
| 30768 | .Extern => offset: { | ||
| 30769 | if (field_size > old_size) @memset(buffer[old_size..], 0xaa); | ||
| 30770 | val.writeToMemory(old_ty, mod, buffer) catch |err| switch (err) { | ||
| 30771 | error.OutOfMemory => return error.OutOfMemory, | ||
| 30772 | error.ReinterpretDeclRef => return null, | ||
| 30773 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already | ||
| 30774 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(mod)}), | ||
| 30775 | }; | ||
| 30776 | break :offset 0; | ||
| 30777 | }, | ||
| 30778 | .Packed => offset: { | ||
| 30779 | if (field_size > old_size) { | ||
| 30780 | const min_size = @max(old_size, 1); | ||
| 30781 | switch (endian) { | ||
| 30782 | .Little => @memset(buffer[min_size - 1 ..], 0xaa), | ||
| 30783 | .Big => @memset(buffer[0 .. buffer.len - min_size + 1], 0xaa), | ||
| 30784 | } | ||
| 30785 | } | ||
| 30786 | |||
| 30787 | val.writeToPackedMemory(old_ty, mod, buffer, 0) catch |err| switch (err) { | ||
| 30788 | error.OutOfMemory => return error.OutOfMemory, | ||
| 30789 | error.ReinterpretDeclRef => return null, | ||
| 30790 | }; | ||
| 30791 | |||
| 30792 | break :offset if (endian == .Big) buffer.len - field_size else 0; | ||
| 30793 | }, | ||
| 30794 | .Auto => unreachable, | ||
| 30795 | }; | ||
| 30772 | 30796 | ||
| 30773 | return Value.readFromMemory(field_ty, mod, buffer[0..], sema.arena) catch |err| switch (err) { | 30797 | return Value.readFromMemory(field_ty, mod, buffer[offset..], sema.arena) catch |err| switch (err) { |
| 30774 | error.OutOfMemory => return error.OutOfMemory, | 30798 | error.OutOfMemory => return error.OutOfMemory, |
| 30775 | error.IllDefinedMemoryLayout => unreachable, | 30799 | error.IllDefinedMemoryLayout => unreachable, |
| 30776 | error.Unimplemented => return sema.fail(block, src, "TODO: implement readFromMemory for type '{}'", .{field_ty.fmt(mod)}), | 30800 | error.Unimplemented => return sema.fail(block, src, "TODO: implement readFromMemory for type '{}'", .{field_ty.fmt(mod)}), |
test/behavior/comptime_memory.zig-161| ... | @@ -455,164 +455,3 @@ test "type pun null pointer-like optional" { | ... | @@ -455,164 +455,3 @@ test "type pun null pointer-like optional" { |
| 455 | // note that expectEqual hides the bug | 455 | // note that expectEqual hides the bug |
| 456 | try testing.expect(@as(*const ?*i8, @ptrCast(&p)).* == null); | 456 | try testing.expect(@as(*const ?*i8, @ptrCast(&p)).* == null); |
| 457 | } | 457 | } |
| 458 | |||
| 459 | test "reinterpret extern union" { | ||
| 460 | const U = extern union { | ||
| 461 | foo: u8, | ||
| 462 | baz: u32 align(8), | ||
| 463 | bar: u32, | ||
| 464 | }; | ||
| 465 | |||
| 466 | comptime { | ||
| 467 | { | ||
| 468 | // Undefined initialization | ||
| 469 | const u = blk: { | ||
| 470 | var u: U = undefined; | ||
| 471 | @memset(std.mem.asBytes(&u), 0); | ||
| 472 | u.bar = 0xbbbbbbbb; | ||
| 473 | u.foo = 0x2a; | ||
| 474 | break :blk u; | ||
| 475 | }; | ||
| 476 | try testing.expectEqual(@as(u8, 0x2a), u.foo); | ||
| 477 | try testing.expectEqual(@as(u32, 0xbbbbbb2a), u.bar); | ||
| 478 | try testing.expectEqual(@as(u64, 0x00000000_bbbbbb2a), u.baz); | ||
| 479 | } | ||
| 480 | |||
| 481 | { | ||
| 482 | // Union initialization | ||
| 483 | var u: U = .{ | ||
| 484 | .foo = 0x2a, | ||
| 485 | }; | ||
| 486 | try testing.expectEqual(@as(u8, 0x2a), u.foo); | ||
| 487 | try testing.expectEqual(@as(u32, 0x2a), u.bar & 0xff); | ||
| 488 | try testing.expectEqual(@as(u64, 0x2a), u.baz & 0xff); | ||
| 489 | |||
| 490 | // Writing to a larger field | ||
| 491 | u = .{ | ||
| 492 | .baz = 0xbbbbbbbb, | ||
| 493 | }; | ||
| 494 | try testing.expectEqual(@as(u8, 0xbb), u.foo); | ||
| 495 | try testing.expectEqual(@as(u32, 0xbbbbbbbb), u.bar); | ||
| 496 | try testing.expectEqual(@as(u64, 0xbbbbbbbb), u.baz); | ||
| 497 | |||
| 498 | // Writing to the same field | ||
| 499 | u = .{ | ||
| 500 | .baz = 0xcccccccc, | ||
| 501 | }; | ||
| 502 | try testing.expectEqual(@as(u8, 0xcc), u.foo); | ||
| 503 | try testing.expectEqual(@as(u32, 0xcccccccc), u.bar); | ||
| 504 | try testing.expectEqual(@as(u64, 0xcccccccc), u.baz); | ||
| 505 | |||
| 506 | // Writing to a smaller field | ||
| 507 | u = .{ | ||
| 508 | .foo = 0xdd, | ||
| 509 | }; | ||
| 510 | try testing.expectEqual(@as(u8, 0xdd), u.foo); | ||
| 511 | try testing.expectEqual(@as(u32, 0xccccccdd), u.bar); | ||
| 512 | try testing.expectEqual(@as(u64, 0xccccccdd), u.baz); | ||
| 513 | } | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | test "reinterpret packed union" { | ||
| 518 | { | ||
| 519 | const U = packed union { | ||
| 520 | a: u32, | ||
| 521 | b: u8 align(8), | ||
| 522 | }; | ||
| 523 | |||
| 524 | comptime { | ||
| 525 | var u: U = undefined; | ||
| 526 | @memset(std.mem.asBytes(&u), 42); | ||
| 527 | try testing.expect(0x2a2a2a2a == u.a); | ||
| 528 | try testing.expect(0x2a == u.b); | ||
| 529 | try testing.expectEqual(@as(u32, 0x2a2a2a2a), u.a); | ||
| 530 | try testing.expectEqual(0x2a, u.b); | ||
| 531 | } | ||
| 532 | } | ||
| 533 | |||
| 534 | { | ||
| 535 | const U = packed union { | ||
| 536 | a: u7, | ||
| 537 | b: u1, | ||
| 538 | }; | ||
| 539 | |||
| 540 | const S = packed struct { | ||
| 541 | lsb: U, | ||
| 542 | msb: U, | ||
| 543 | }; | ||
| 544 | |||
| 545 | comptime { | ||
| 546 | var s: S = undefined; | ||
| 547 | @memset(std.mem.asBytes(&s), 0x55); | ||
| 548 | try testing.expectEqual(@as(u7, 0x55), s.lsb.a); | ||
| 549 | try testing.expectEqual(@as(u1, 1), s.lsb.b); | ||
| 550 | try testing.expectEqual(@as(u7, 0x2a), s.msb.a); | ||
| 551 | try testing.expectEqual(@as(u1, 0), s.msb.b); | ||
| 552 | |||
| 553 | s.lsb.b = 0; | ||
| 554 | try testing.expectEqual(@as(u7, 0x54), s.lsb.a); | ||
| 555 | try testing.expectEqual(@as(u1, 0), s.lsb.b); | ||
| 556 | s.msb.b = 1; | ||
| 557 | try testing.expectEqual(@as(u7, 0x2b), s.msb.a); | ||
| 558 | try testing.expectEqual(@as(u1, 1), s.msb.b); | ||
| 559 | } | ||
| 560 | } | ||
| 561 | |||
| 562 | { | ||
| 563 | const U = packed union { | ||
| 564 | foo: u8, | ||
| 565 | bar: u29, | ||
| 566 | baz: u64, | ||
| 567 | }; | ||
| 568 | |||
| 569 | comptime { | ||
| 570 | { | ||
| 571 | const u = blk: { | ||
| 572 | var u: U = undefined; | ||
| 573 | @memset(std.mem.asBytes(&u), 0); | ||
| 574 | u.baz = 0xbbbbbbbb; | ||
| 575 | u.foo = 0x2a; | ||
| 576 | break :blk u; | ||
| 577 | }; | ||
| 578 | try testing.expectEqual(@as(u8, 0x2a), u.foo); | ||
| 579 | try testing.expectEqual(@as(u29, 0x1bbbbb2a), u.bar); | ||
| 580 | try testing.expectEqual(@as(u64, 0x00000000_bbbbbb2a), u.baz); | ||
| 581 | } | ||
| 582 | |||
| 583 | { | ||
| 584 | // Union initialization | ||
| 585 | var u: U = .{ | ||
| 586 | .foo = 0x2a, | ||
| 587 | }; | ||
| 588 | try testing.expectEqual(@as(u8, 0x2a), u.foo); | ||
| 589 | try testing.expectEqual(@as(u29, 0x2a), u.bar & 0xff); | ||
| 590 | try testing.expectEqual(@as(u64, 0x2a), u.baz & 0xff); | ||
| 591 | |||
| 592 | // Writing to a larger field | ||
| 593 | u = .{ | ||
| 594 | .baz = 0xbbbbbbbb, | ||
| 595 | }; | ||
| 596 | try testing.expectEqual(@as(u8, 0xbb), u.foo); | ||
| 597 | try testing.expectEqual(@as(u29, 0x1bbbbbbb), u.bar); | ||
| 598 | try testing.expectEqual(@as(u64, 0xbbbbbbbb), u.baz); | ||
| 599 | |||
| 600 | // Writing to the same field | ||
| 601 | u = .{ | ||
| 602 | .baz = 0xcccccccc, | ||
| 603 | }; | ||
| 604 | try testing.expectEqual(@as(u8, 0xcc), u.foo); | ||
| 605 | try testing.expectEqual(@as(u29, 0x0ccccccc), u.bar); | ||
| 606 | try testing.expectEqual(@as(u64, 0xcccccccc), u.baz); | ||
| 607 | |||
| 608 | // Writing to a smaller field | ||
| 609 | u = .{ | ||
| 610 | .foo = 0xdd, | ||
| 611 | }; | ||
| 612 | try testing.expectEqual(@as(u8, 0xdd), u.foo); | ||
| 613 | try testing.expectEqual(@as(u29, 0x0cccccdd), u.bar); | ||
| 614 | try testing.expectEqual(@as(u64, 0xccccccdd), u.baz); | ||
| 615 | } | ||
| 616 | } | ||
| 617 | } | ||
| 618 | } |
test/behavior/union.zig+212-7| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | const endian = builtin.cpu.arch.endian(); | ||
| 3 | const expect = std.testing.expect; | 4 | const expect = std.testing.expect; |
| 4 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 5 | const expectEqual = std.testing.expectEqual; | 6 | const expectEqual = std.testing.expectEqual; |
| ... | @@ -1660,15 +1661,219 @@ test "union with 128 bit integer" { | ... | @@ -1660,15 +1661,219 @@ test "union with 128 bit integer" { |
| 1660 | } | 1661 | } |
| 1661 | } | 1662 | } |
| 1662 | 1663 | ||
| 1663 | test "memset extern union at comptime" { | 1664 | test "memset extern union" { |
| 1664 | const U = extern union { | 1665 | const U = extern union { |
| 1665 | foo: u8, | 1666 | foo: u8, |
| 1667 | bar: u32, | ||
| 1668 | }; | ||
| 1669 | |||
| 1670 | const S = struct { | ||
| 1671 | fn doTheTest() !void { | ||
| 1672 | var u: U = undefined; | ||
| 1673 | @memset(std.mem.asBytes(&u), 0); | ||
| 1674 | try expectEqual(@as(u8, 0), u.foo); | ||
| 1675 | try expectEqual(@as(u32, 0), u.bar); | ||
| 1676 | } | ||
| 1677 | }; | ||
| 1678 | |||
| 1679 | try comptime S.doTheTest(); | ||
| 1680 | try S.doTheTest(); | ||
| 1681 | } | ||
| 1682 | |||
| 1683 | test "memset packed union" { | ||
| 1684 | const U = packed union { | ||
| 1685 | a: u32, | ||
| 1686 | b: u8, | ||
| 1687 | }; | ||
| 1688 | |||
| 1689 | const S = struct { | ||
| 1690 | fn doTheTest() !void { | ||
| 1691 | var u: U = undefined; | ||
| 1692 | @memset(std.mem.asBytes(&u), 42); | ||
| 1693 | try expectEqual(@as(u32, 0x2a2a2a2a), u.a); | ||
| 1694 | try expectEqual(@as(u8, 0x2a), u.b); | ||
| 1695 | } | ||
| 1696 | }; | ||
| 1697 | |||
| 1698 | try comptime S.doTheTest(); | ||
| 1699 | |||
| 1700 | if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; // TODO | ||
| 1701 | try S.doTheTest(); | ||
| 1702 | } | ||
| 1703 | |||
| 1704 | fn littleToNativeEndian(comptime T: type, v: T) T { | ||
| 1705 | return if (endian == .Little) v else @byteSwap(v); | ||
| 1706 | } | ||
| 1707 | |||
| 1708 | test "reinterpret extern union" { | ||
| 1709 | const U = extern union { | ||
| 1710 | foo: u8, | ||
| 1711 | baz: u32 align(8), | ||
| 1712 | bar: u32, | ||
| 1713 | }; | ||
| 1714 | |||
| 1715 | const S = struct { | ||
| 1716 | fn doTheTest() !void { | ||
| 1717 | { | ||
| 1718 | // Undefined initialization | ||
| 1719 | const u = blk: { | ||
| 1720 | var u: U = undefined; | ||
| 1721 | @memset(std.mem.asBytes(&u), 0); | ||
| 1722 | u.bar = 0xbbbbbbbb; | ||
| 1723 | u.foo = 0x2a; | ||
| 1724 | break :blk u; | ||
| 1725 | }; | ||
| 1726 | |||
| 1727 | try expectEqual(@as(u8, 0x2a), u.foo); | ||
| 1728 | try expectEqual(littleToNativeEndian(u32, 0xbbbbbb2a), u.bar); | ||
| 1729 | try expectEqual(littleToNativeEndian(u32, 0xbbbbbb2a), u.baz); | ||
| 1730 | } | ||
| 1731 | |||
| 1732 | { | ||
| 1733 | // Union initialization | ||
| 1734 | var u: U = .{ | ||
| 1735 | .foo = 0x2a, | ||
| 1736 | }; | ||
| 1737 | |||
| 1738 | { | ||
| 1739 | const expected, const mask = switch (endian) { | ||
| 1740 | .Little => .{ 0x2a, 0xff }, | ||
| 1741 | .Big => .{ 0x2a000000, 0xff000000 }, | ||
| 1742 | }; | ||
| 1743 | |||
| 1744 | try expectEqual(@as(u8, 0x2a), u.foo); | ||
| 1745 | try expectEqual(@as(u32, expected), u.bar & mask); | ||
| 1746 | try expectEqual(@as(u32, expected), u.baz & mask); | ||
| 1747 | } | ||
| 1748 | |||
| 1749 | // Writing to a larger field | ||
| 1750 | u.baz = 0xbbbbbbbb; | ||
| 1751 | try expectEqual(@as(u8, 0xbb), u.foo); | ||
| 1752 | try expectEqual(@as(u32, 0xbbbbbbbb), u.bar); | ||
| 1753 | try expectEqual(@as(u32, 0xbbbbbbbb), u.baz); | ||
| 1754 | |||
| 1755 | // Writing to the same field | ||
| 1756 | u.baz = 0xcccccccc; | ||
| 1757 | try expectEqual(@as(u8, 0xcc), u.foo); | ||
| 1758 | try expectEqual(@as(u32, 0xcccccccc), u.bar); | ||
| 1759 | try expectEqual(@as(u32, 0xcccccccc), u.baz); | ||
| 1760 | |||
| 1761 | // Writing to a smaller field | ||
| 1762 | u.foo = 0xdd; | ||
| 1763 | try expectEqual(@as(u8, 0xdd), u.foo); | ||
| 1764 | try expectEqual(littleToNativeEndian(u32, 0xccccccdd), u.bar); | ||
| 1765 | try expectEqual(littleToNativeEndian(u32, 0xccccccdd), u.baz); | ||
| 1766 | } | ||
| 1767 | } | ||
| 1768 | }; | ||
| 1769 | |||
| 1770 | try comptime S.doTheTest(); | ||
| 1771 | |||
| 1772 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO | ||
| 1773 | try S.doTheTest(); | ||
| 1774 | } | ||
| 1775 | |||
| 1776 | test "reinterpret packed union" { | ||
| 1777 | const U = packed union { | ||
| 1778 | foo: u8, | ||
| 1779 | bar: u29, | ||
| 1780 | baz: u64, | ||
| 1781 | qux: u12, | ||
| 1782 | }; | ||
| 1783 | |||
| 1784 | const S = struct { | ||
| 1785 | fn doTheTest() !void { | ||
| 1786 | { | ||
| 1787 | const u = blk: { | ||
| 1788 | var u: U = undefined; | ||
| 1789 | @memset(std.mem.asBytes(&u), 0); | ||
| 1790 | u.baz = 0xbbbbbbbb; | ||
| 1791 | u.qux = 0xe2a; | ||
| 1792 | break :blk u; | ||
| 1793 | }; | ||
| 1794 | |||
| 1795 | try expectEqual(@as(u8, 0x2a), u.foo); | ||
| 1796 | try expectEqual(@as(u12, 0xe2a), u.qux); | ||
| 1797 | |||
| 1798 | // https://github.com/ziglang/zig/issues/17360 | ||
| 1799 | if (@inComptime()) { | ||
| 1800 | try expectEqual(@as(u29, 0x1bbbbe2a), u.bar); | ||
| 1801 | try expectEqual(@as(u64, 0xbbbbbe2a), u.baz); | ||
| 1802 | } | ||
| 1803 | } | ||
| 1804 | |||
| 1805 | { | ||
| 1806 | // Union initialization | ||
| 1807 | var u: U = .{ | ||
| 1808 | .qux = 0xe2a, | ||
| 1809 | }; | ||
| 1810 | try expectEqual(@as(u8, 0x2a), u.foo); | ||
| 1811 | try expectEqual(@as(u12, 0xe2a), u.qux); | ||
| 1812 | try expectEqual(@as(u29, 0xe2a), u.bar & 0xfff); | ||
| 1813 | try expectEqual(@as(u64, 0xe2a), u.baz & 0xfff); | ||
| 1814 | |||
| 1815 | // Writing to a larger field | ||
| 1816 | u.baz = 0xbbbbbbbb; | ||
| 1817 | try expectEqual(@as(u8, 0xbb), u.foo); | ||
| 1818 | try expectEqual(@as(u12, 0xbbb), u.qux); | ||
| 1819 | try expectEqual(@as(u29, 0x1bbbbbbb), u.bar); | ||
| 1820 | try expectEqual(@as(u64, 0xbbbbbbbb), u.baz); | ||
| 1821 | |||
| 1822 | // Writing to the same field | ||
| 1823 | u.baz = 0xcccccccc; | ||
| 1824 | try expectEqual(@as(u8, 0xcc), u.foo); | ||
| 1825 | try expectEqual(@as(u12, 0xccc), u.qux); | ||
| 1826 | try expectEqual(@as(u29, 0x0ccccccc), u.bar); | ||
| 1827 | try expectEqual(@as(u64, 0xcccccccc), u.baz); | ||
| 1828 | |||
| 1829 | // Writing to a smaller field | ||
| 1830 | u.foo = 0xdd; | ||
| 1831 | try expectEqual(@as(u8, 0xdd), u.foo); | ||
| 1832 | try expectEqual(@as(u12, 0xcdd), u.qux); | ||
| 1833 | try expectEqual(@as(u29, 0x0cccccdd), u.bar); | ||
| 1834 | try expectEqual(@as(u64, 0xccccccdd), u.baz); | ||
| 1835 | } | ||
| 1836 | } | ||
| 1666 | }; | 1837 | }; |
| 1667 | const u = comptime blk: { | 1838 | |
| 1668 | var u: U = undefined; | 1839 | try comptime S.doTheTest(); |
| 1669 | @memset(std.mem.asBytes(&u), 0); | 1840 | |
| 1670 | u.foo = 0; | 1841 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1671 | break :blk u; | 1842 | if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; // TODO |
| 1843 | try S.doTheTest(); | ||
| 1844 | } | ||
| 1845 | |||
| 1846 | test "reinterpret packed union inside packed struct" { | ||
| 1847 | const U = packed union { | ||
| 1848 | a: u7, | ||
| 1849 | b: u1, | ||
| 1850 | }; | ||
| 1851 | |||
| 1852 | const V = packed struct { | ||
| 1853 | lo: U, | ||
| 1854 | hi: U, | ||
| 1672 | }; | 1855 | }; |
| 1673 | try expect(u.foo == 0); | 1856 | |
| 1857 | const S = struct { | ||
| 1858 | fn doTheTest() !void { | ||
| 1859 | var v: V = undefined; | ||
| 1860 | @memset(std.mem.asBytes(&v), 0x55); | ||
| 1861 | try expectEqual(@as(u7, 0x55), v.lo.a); | ||
| 1862 | try expectEqual(@as(u1, 1), v.lo.b); | ||
| 1863 | try expectEqual(@as(u7, 0x2a), v.hi.a); | ||
| 1864 | try expectEqual(@as(u1, 0), v.hi.b); | ||
| 1865 | |||
| 1866 | v.lo.b = 0; | ||
| 1867 | try expectEqual(@as(u7, 0x54), v.lo.a); | ||
| 1868 | try expectEqual(@as(u1, 0), v.lo.b); | ||
| 1869 | v.hi.b = 1; | ||
| 1870 | try expectEqual(@as(u7, 0x2b), v.hi.a); | ||
| 1871 | try expectEqual(@as(u1, 1), v.hi.b); | ||
| 1872 | } | ||
| 1873 | }; | ||
| 1874 | |||
| 1875 | try comptime S.doTheTest(); | ||
| 1876 | |||
| 1877 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 1878 | try S.doTheTest(); | ||
| 1674 | } | 1879 | } |