authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-20 19:40:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-21 14:48:40-07:00
logdca17d3603e5b68a8f683bfc1bdabc9959654d26
tree285502dd184921918e0ad3b2d34c1d3fdef1830b
parentd06bf707ed374ca42a580ee7acf1cecaab078d0d

Sema: fix struct alignment regressions


2 files changed, 50 insertions(+), 23 deletions(-)

src/InternPool.zig+17-1
......@@ -536,6 +536,19 @@ pub const Key = union(enum) {
536536 s.flagsPtr(ip).layout_wip = false;
537537 }
538538
539 pub fn setAlignmentWip(s: @This(), ip: *InternPool) bool {
540 if (s.layout == .Packed) return false;
541 const flags_ptr = s.flagsPtr(ip);
542 if (flags_ptr.alignment_wip) return true;
543 flags_ptr.alignment_wip = true;
544 return false;
545 }
546
547 pub fn clearAlignmentWip(s: @This(), ip: *InternPool) void {
548 if (s.layout == .Packed) return;
549 s.flagsPtr(ip).alignment_wip = false;
550 }
551
539552 pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {
540553 if (s.layout == .Packed) return true;
541554 const flags_ptr = s.flagsPtr(ip);
......@@ -2971,6 +2984,8 @@ pub const Tag = enum(u8) {
29712984 any_aligned_fields: bool,
29722985 /// `undefined` until the layout_resolved
29732986 alignment: Alignment,
2987 /// Dependency loop detection when resolving struct alignment.
2988 alignment_wip: bool,
29742989 /// Dependency loop detection when resolving field types.
29752990 field_types_wip: bool,
29762991 /// Dependency loop detection when resolving struct layout.
......@@ -2982,7 +2997,7 @@ pub const Tag = enum(u8) {
29822997 // which `layout_resolved` does not ensure.
29832998 fully_resolved: bool,
29842999
2985 _: u12 = 0,
3000 _: u11 = 0,
29863001 };
29873002 };
29883003};
......@@ -5300,6 +5315,7 @@ pub fn getStructType(
53005315 .any_default_inits = ini.any_default_inits,
53015316 .any_aligned_fields = ini.any_aligned_fields,
53025317 .alignment = .none,
5318 .alignment_wip = false,
53035319 .field_types_wip = false,
53045320 .layout_wip = false,
53055321 .layout_resolved = false,
src/Sema.zig+33-22
......@@ -26698,21 +26698,25 @@ fn structFieldPtrByIndex(
2669826698 }
2669926699 }
2670026700 } else if (struct_type.layout == .Extern) {
26701 // For extern structs, field aligment might be bigger than type's natural alignment. Eg, in
26702 // `extern struct { x: u32, y: u16 }` the second field is aligned as u32.
26701 // For extern structs, field alignment might be bigger than type's
26702 // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
26703 // second field is aligned as u32.
2670326704 const field_offset = struct_ty.structFieldOffset(field_index, mod);
2670426705 ptr_ty_data.flags.alignment = if (parent_align == .none)
2670526706 .none
2670626707 else
2670726708 @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset)));
2670826709 } else {
26709 // Our alignment is capped at the field alignment
26710 // Our alignment is capped at the field alignment.
2671026711 const field_align = try sema.structFieldAlignment(
2671126712 struct_type.fieldAlign(ip, field_index),
2671226713 field_ty.toType(),
2671326714 struct_type.layout,
2671426715 );
26715 ptr_ty_data.flags.alignment = field_align.min(parent_align);
26716 ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none)
26717 field_align
26718 else
26719 field_align.min(parent_align);
2671626720 }
2671726721
2671826722 const ptr_field_ty = try sema.ptrType(ptr_ty_data);
......@@ -28635,8 +28639,8 @@ const InMemoryCoercionResult = union(enum) {
2863528639 break;
2863628640 },
2863728641 .ptr_alignment => |pair| {
28638 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{
28639 pair.actual, pair.wanted,
28642 try sema.errNote(block, src, msg, "pointer alignment '{d}' cannot cast into pointer alignment '{d}'", .{
28643 pair.actual.toByteUnits(0), pair.wanted.toByteUnits(0),
2864028644 });
2864128645 break;
2864228646 },
......@@ -34307,20 +34311,29 @@ pub fn resolveStructAlignment(
3430734311
3430834312 try sema.resolveTypeFieldsStruct(ty, struct_type);
3430934313
34314 if (struct_type.setAlignmentWip(ip)) {
34315 // We'll guess "pointer-aligned", if the struct has an
34316 // underaligned pointer field then some allocations
34317 // might require explicit alignment.
34318 //TODO write this bit and emit an error later if incorrect
34319 //struct_type.flagsPtr(ip).assumed_pointer_aligned = true;
34320 const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
34321 struct_type.flagsPtr(ip).alignment = result;
34322 return result;
34323 }
34324
3431034325 var result: Alignment = .@"1";
3431134326
3431234327 for (0..struct_type.field_types.len) |i| {
34313 if (struct_type.fieldIsComptime(ip, i)) continue;
3431434328 const field_ty = struct_type.field_types.get(ip)[i].toType();
34315 if (try sema.typeRequiresComptime(field_ty)) continue;
34316 if (try sema.typeHasRuntimeBits(field_ty)) {
34317 const field_align = try sema.structFieldAlignment(
34318 struct_type.fieldAlign(ip, i),
34319 field_ty,
34320 struct_type.layout,
34321 );
34322 result = result.max(field_align);
34323 }
34329 if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty))
34330 continue;
34331 const field_align = try sema.structFieldAlignment(
34332 struct_type.fieldAlign(ip, i),
34333 field_ty,
34334 struct_type.layout,
34335 );
34336 result = result.max(field_align);
3432434337 }
3432534338
3432634339 struct_type.flagsPtr(ip).alignment = result;
......@@ -34358,7 +34371,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
3435834371
3435934372 for (aligns, sizes, 0..) |*field_align, *field_size, i| {
3436034373 const field_ty = struct_type.field_types.get(ip)[i].toType();
34361 if (struct_type.fieldIsComptime(ip, i) or !(try sema.typeHasRuntimeBits(field_ty))) {
34374 if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) {
3436234375 struct_type.offsets.get(ip)[i] = 0;
3436334376 field_size.* = 0;
3436434377 field_align.* = .none;
......@@ -34439,10 +34452,8 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
3443934452 var offset: u64 = 0;
3444034453 var big_align: Alignment = .@"1";
3444134454 while (it.next()) |i| {
34442 const field_ty = struct_type.field_types.get(ip)[i].toType();
34443 // Type query definitely valid as we performed it earlier
34444 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
34445 big_align = big_align.max(aligns[i]);
34455 if (aligns[i] == .none) continue;
34456 big_align = big_align.maxStrict(aligns[i]);
3444634457 offsets[i] = @intCast(aligns[i].forward(offset));
3444734458 offset = offsets[i] + sizes[i];
3444834459 }
......@@ -36870,7 +36881,7 @@ fn structFieldAlignment(
3687036881 // extern
3687136882 const ty_abi_align = try sema.typeAbiAlignment(field_ty);
3687236883 if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {
36873 return ty_abi_align.max(.@"16");
36884 return ty_abi_align.maxStrict(.@"16");
3687436885 }
3687536886 return ty_abi_align;
3687636887}