From 459f3b7edef14da7d9ec29a77329601469f08b36 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 3 Nov 2025 22:33:10 -0500 Subject: [PATCH] codegen: fix tuple padding Closes #25797 --- src/codegen.zig | 37 ++++++++++++------------------------- test/behavior/tuple.zig | 12 ++++++++++++ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/codegen.zig b/src/codegen.zig index caff954e07..6bdfa32f45 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -534,9 +534,7 @@ pub fn generateSymbol( while (index < vector_type.len) : (index += 1) { try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (aggregate.storage) { .bytes => unreachable, - .elems => |elems| elems[ - math.cast(usize, index) orelse return error.Overflow - ], + .elems => |elems| elems[math.cast(usize, index) orelse return error.Overflow], .repeated_elem => |elem| elem, }), w, reloc_parent); } @@ -551,35 +549,24 @@ pub fn generateSymbol( }, .tuple_type => |tuple| { const struct_begin = w.end; - for ( - tuple.types.get(ip), - tuple.values.get(ip), - 0.., - ) |field_ty, comptime_val, index| { - if (comptime_val != .none) continue; + for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, field_index| { + if (field_val != .none) continue; if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue; - const field_val = switch (aggregate.storage) { + try w.splatByteAll(0, math.cast(usize, struct_begin + + Type.fromInterned(field_ty).abiAlignment(zcu).forward(w.end - struct_begin) - w.end) orelse + return error.Overflow); + try generateSymbol(bin_file, pt, src_loc, .fromInterned(switch (aggregate.storage) { .bytes => |bytes| try pt.intern(.{ .int = .{ .ty = field_ty, - .storage = .{ .u64 = bytes.at(index, ip) }, + .storage = .{ .u64 = bytes.at(field_index, ip) }, } }), - .elems => |elems| elems[index], + .elems => |elems| elems[field_index], .repeated_elem => |elem| elem, - }; - - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); - const unpadded_field_end = w.end - struct_begin; - - // Pad struct members if required - const padded_field_end = ty.structFieldOffset(index + 1, zcu); - const padding = math.cast(usize, padded_field_end - unpadded_field_end) orelse - return error.Overflow; - - if (padding > 0) { - try w.splatByteAll(0, padding); - } + }), w, reloc_parent); } + try w.splatByteAll(0, math.cast(usize, struct_begin + ty.abiSize(zcu) - w.end) orelse + return error.Overflow); }, .struct_type => { const struct_type = ip.loadStructType(ty.toIntern()); diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 54d73eee8a..cc9a711f20 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -631,3 +631,15 @@ test "OPV tuple fields aren't comptime" { const t2_info = @typeInfo(T2); try expect(!t2_info.@"struct".fields[0].is_comptime); } + +test "array of tuples that end with a zero-bit field followed by padding" { + const S = struct { + var foo: [2]struct { u32, u8, void } = .{ .{ 1, 2, {} }, .{ 3, 4, {} } }; + }; + try expect(S.foo[0][0] == 1); + try expect(S.foo[0][1] == 2); + try expect(S.foo[0][2] == {}); + try expect(S.foo[1][0] == 3); + try expect(S.foo[1][1] == 4); + try expect(S.foo[1][2] == {}); +}