diff --git a/src/Sema/comptime_ptr_access.zig b/src/Sema/comptime_ptr_access.zig index ceddb9457df9..0fdcddd82133 100644 --- a/src/Sema/comptime_ptr_access.zig +++ b/src/Sema/comptime_ptr_access.zig @@ -748,7 +748,7 @@ fn prepareComptimePtrStore( const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: { if (try store_one_ty.comptimeOnlySema(pt)) break :restructure_array; const elem_len = try store_one_ty.abiSizeSema(pt); - if (ptr.byte_offset % elem_len != 0) break :restructure_array; + if (elem_len == 0 or ptr.byte_offset % elem_len != 0) break :restructure_array; break :idx @divExact(ptr.byte_offset, elem_len); }; @@ -857,8 +857,18 @@ fn prepareComptimePtrStore( .array => { const elem_ty = cur_ty.childType(zcu); const elem_size = try elem_ty.abiSizeSema(pt); - const elem_idx = cur_offset / elem_size; - const next_elem_off = elem_size * (elem_idx + 1); + + const elem_idx, const next_elem_off = if (elem_size == 0) + .{ 0, 1 } + else idx: { + const elem_inner_idx = (cur_offset % elem_size); + + // The index would be out of bounds if we don't check for 0-bit values located at the end of the element type. + const elem_idx = (cur_offset / elem_size) - @as(u64, if (cur_offset != 0 and elem_inner_idx == 0 and need_bytes == 0) 1 else 0); + const next_elem_off = elem_size * (elem_idx + 1); + break :idx .{ elem_idx, next_elem_off }; + }; + if (cur_offset + need_bytes <= next_elem_off) { // We can look at a single array element. cur_val = try cur_val.elem(pt, sema.arena, @intCast(elem_idx)); diff --git a/test/behavior/void.zig b/test/behavior/void.zig index ec2654fc833c..6f95ee704dd1 100644 --- a/test/behavior/void.zig +++ b/test/behavior/void.zig @@ -55,3 +55,58 @@ test "reference to void constants" { var a = void_constant; _ = &a; } + +// See issue #23307 +const Bar = extern struct { + a: u8, + b: u8, + c: void, +}; + +test "store void in extern struct through a pointer at compile-time" { + comptime { + var x: Bar = undefined; + const y = &x; + y.* = Bar{ + .a = 0, + .b = 1, + .c = {}, + }; + } +} + +test "store void in extern struct inside an array at compile-time" { + comptime { + var x: [5]Bar = undefined; + + for (&x) |*y| y.* = .{ + .a = 0, + .b = 1, + .c = {}, + }; + } +} + +const PackedBar = packed struct(u8) { a: u8, b: void }; + +test "store void in packed struct through a pointer at compile-time" { + comptime { + var x: PackedBar = undefined; + const y = &x; + y.* = PackedBar{ + .a = 0, + .b = {}, + }; + } +} + +test "store void in packed struct inside an array at compile-time" { + comptime { + var x: [5]PackedBar = undefined; + + for (&x) |*y| y.* = .{ + .a = 0, + .b = {}, + }; + } +}