Skip to content

Commit f83fe27

Browse files
committed
compiler: fix comptime memory store bugs
* 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: ziglang#21202 Resolves: ziglang#21508 Resolves: ziglang#23307
1 parent ae1b444 commit f83fe27

File tree

3 files changed

+73
-4
lines changed

3 files changed

+73
-4
lines changed

src/Sema/comptime_ptr_access.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ pub fn storeComptimePtr(
6565
const zcu = pt.zcu;
6666
const ptr_info = ptr.typeOf(zcu).ptrInfo(zcu);
6767
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+
6877
// TODO: host size for vectors is terrible
6978
const host_bits = switch (ptr_info.flags.vector_index) {
7079
.none => ptr_info.packed_offset.host_size * 8,

src/Type.zig

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,10 +1637,7 @@ pub fn bitSizeInner(
16371637
const len = array_type.lenIncludingSentinel();
16381638
if (len == 0) return 0;
16391639
const elem_ty = Type.fromInterned(array_type.child);
1640-
const elem_size = @max(
1641-
(try elem_ty.abiAlignmentInner(strat_lazy, zcu, tid)).scalar.toByteUnits() orelse 0,
1642-
(try elem_ty.abiSizeInner(strat_lazy, zcu, tid)).scalar,
1643-
);
1640+
const elem_size = (try elem_ty.abiSizeInner(strat_lazy, zcu, tid)).scalar;
16441641
if (elem_size == 0) return 0;
16451642
const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid);
16461643
return (len - 1) * 8 * elem_size + elem_bit_size;

test/behavior/comptime_memory.zig

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,3 +515,66 @@ fn fieldPtrTest() u32 {
515515
test "pointer in aggregate field can mutate comptime state" {
516516
try comptime std.testing.expect(fieldPtrTest() == 2);
517517
}
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+
}

0 commit comments

Comments
 (0)