| author | |
| committer | |
| log | db936b909471f5c7e0344489ab1e7d59ab387658 |
| tree | 733ceb4aaa6906ab70e1efab581a98b22bdfe50b |
| parent | 87983e800a2bd5a2369d49facb70e1a7854efeaa |
| signature |
* When storing a zero-bit type, we should short-circuit almost
immediately. Zero-bit stores do not need to do any work.
* The bit size computation for arrays is incorrect; the `abiSize` will
already be appropriately aligned, but the logic to do so here
incorrectly assumes that zero-bit types have an alignment of 0. They
don't; their alignment is 1.
Resolves: #21202
Resolves: #21508
Resolves: #233073 files changed, 73 insertions(+), 4 deletions(-)
src/Sema/comptime_ptr_access.zig+9| ... | @@ -65,6 +65,15 @@ pub fn storeComptimePtr( | ... | @@ -65,6 +65,15 @@ pub fn storeComptimePtr( |
| 65 | const zcu = pt.zcu; | 65 | const zcu = pt.zcu; |
| 66 | const ptr_info = ptr.typeOf(zcu).ptrInfo(zcu); | 66 | const ptr_info = ptr.typeOf(zcu).ptrInfo(zcu); |
| 67 | assert(store_val.typeOf(zcu).toIntern() == ptr_info.child); | 67 | assert(store_val.typeOf(zcu).toIntern() == ptr_info.child); |
| 68 | |||
| 69 | { | ||
| 70 | const store_ty: Type = .fromInterned(ptr_info.child); | ||
| 71 | if (!try store_ty.comptimeOnlySema(pt) and !try store_ty.hasRuntimeBitsIgnoreComptimeSema(pt)) { | ||
| 72 | // zero-bit store; nothing to do | ||
| 73 | return .success; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 68 | // TODO: host size for vectors is terrible | 77 | // TODO: host size for vectors is terrible |
| 69 | const host_bits = switch (ptr_info.flags.vector_index) { | 78 | const host_bits = switch (ptr_info.flags.vector_index) { |
| 70 | .none => ptr_info.packed_offset.host_size * 8, | 79 | .none => ptr_info.packed_offset.host_size * 8, |
src/Type.zig+1-4| ... | @@ -1740,10 +1740,7 @@ pub fn bitSizeInner( | ... | @@ -1740,10 +1740,7 @@ pub fn bitSizeInner( |
| 1740 | const len = array_type.lenIncludingSentinel(); | 1740 | const len = array_type.lenIncludingSentinel(); |
| 1741 | if (len == 0) return 0; | 1741 | if (len == 0) return 0; |
| 1742 | const elem_ty = Type.fromInterned(array_type.child); | 1742 | const elem_ty = Type.fromInterned(array_type.child); |
| 1743 | const elem_size = @max( | 1743 | const elem_size = (try elem_ty.abiSizeInner(strat_lazy, zcu, tid)).scalar; |
| 1744 | (try elem_ty.abiAlignmentInner(strat_lazy, zcu, tid)).scalar.toByteUnits() orelse 0, | ||
| 1745 | (try elem_ty.abiSizeInner(strat_lazy, zcu, tid)).scalar, | ||
| 1746 | ); | ||
| 1747 | if (elem_size == 0) return 0; | 1744 | if (elem_size == 0) return 0; |
| 1748 | const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid); | 1745 | const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid); |
| 1749 | return (len - 1) * 8 * elem_size + elem_bit_size; | 1746 | return (len - 1) * 8 * elem_size + elem_bit_size; |
test/behavior/comptime_memory.zig+63| ... | @@ -515,3 +515,66 @@ fn fieldPtrTest() u32 { | ... | @@ -515,3 +515,66 @@ fn fieldPtrTest() u32 { |
| 515 | test "pointer in aggregate field can mutate comptime state" { | 515 | test "pointer in aggregate field can mutate comptime state" { |
| 516 | try comptime std.testing.expect(fieldPtrTest() == 2); | 516 | try comptime std.testing.expect(fieldPtrTest() == 2); |
| 517 | } | 517 | } |
| 518 | |||
| 519 | test "comptime store of extern struct with void field" { | ||
| 520 | comptime { | ||
| 521 | var x: extern struct { a: u8, b: void } = undefined; | ||
| 522 | x = .{ .a = 123, .b = {} }; | ||
| 523 | std.debug.assert(x.a == 123); | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 | test "comptime store of extern struct with void field into array" { | ||
| 528 | comptime { | ||
| 529 | var x: [3]extern struct { a: u8, b: void } = undefined; | ||
| 530 | x[1] = .{ .a = 123, .b = {} }; | ||
| 531 | std.debug.assert(x[1].a == 123); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | test "comptime store of packed struct with void field" { | ||
| 536 | comptime { | ||
| 537 | var x: packed struct { a: u8, b: void } = undefined; | ||
| 538 | x = .{ .a = 123, .b = {} }; | ||
| 539 | std.debug.assert(x.a == 123); | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | test "comptime store of packed struct with void field into array" { | ||
| 544 | comptime { | ||
| 545 | var x: [3]packed struct { a: u8, b: void } = undefined; | ||
| 546 | x[1] = .{ .a = 123, .b = {} }; | ||
| 547 | std.debug.assert(x[1].a == 123); | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | test "comptime store of reinterpreted zero-bit type" { | ||
| 552 | const S = struct { | ||
| 553 | fn doTheTest(comptime T: type) void { | ||
| 554 | comptime var buf: T = undefined; | ||
| 555 | const ptr: *void = @ptrCast(&buf); | ||
| 556 | ptr.* = {}; | ||
| 557 | } | ||
| 558 | }; | ||
| 559 | S.doTheTest(void); | ||
| 560 | S.doTheTest(u0); | ||
| 561 | S.doTheTest([0]u8); | ||
| 562 | S.doTheTest([1]u0); | ||
| 563 | S.doTheTest([5]u0); | ||
| 564 | S.doTheTest([5]void); | ||
| 565 | S.doTheTest(packed struct(u0) {}); | ||
| 566 | } | ||
| 567 | |||
| 568 | test "comptime store to extern struct reinterpreted as byte array" { | ||
| 569 | const T = extern struct { | ||
| 570 | x: u32, | ||
| 571 | y: f32, | ||
| 572 | z: [2]void, | ||
| 573 | }; | ||
| 574 | comptime var val: T = undefined; | ||
| 575 | |||
| 576 | const bytes: *[@sizeOf(T)]u8 = @ptrCast(&val); | ||
| 577 | @memset(bytes, 0); | ||
| 578 | |||
| 579 | comptime std.debug.assert(val.x == 0); | ||
| 580 | } |