Sema: fix dependency loop regression on struct field alignment

This commit is contained in:
Andrew Kelley 2023-09-20 16:44:10 -07:00
parent 2671aa9058
commit 5ea3de55c4
2 changed files with 57 additions and 18 deletions

View File

@ -34280,9 +34280,54 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
}
}
fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
try sema.resolveTypeFields(ty);
/// Resolve a struct's alignment only without triggering resolution of its layout.
/// Asserts that the alignment is not yet resolved and the layout is non-packed.
pub fn resolveStructAlignment(
sema: *Sema,
ty: InternPool.Index,
struct_type: InternPool.Key.StructType,
) CompileError!Alignment {
const mod = sema.mod;
const ip = &mod.intern_pool;
const target = mod.getTarget();
assert(struct_type.flagsPtr(ip).alignment == .none);
assert(struct_type.layout != .Packed);
if (struct_type.flagsPtr(ip).field_types_wip) {
// We'll guess "pointer-aligned", if the struct has an
// underaligned pointer field then some allocations
// might require explicit alignment.
//TODO write this bit and emit an error later if incorrect
//struct_type.flagsPtr(ip).assumed_pointer_aligned = true;
const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
struct_type.flagsPtr(ip).alignment = result;
return result;
}
try sema.resolveTypeFieldsStruct(ty, struct_type);
var result: Alignment = .@"1";
for (0..struct_type.field_types.len) |i| {
if (struct_type.fieldIsComptime(ip, i)) continue;
const field_ty = struct_type.field_types.get(ip)[i].toType();
if (try sema.typeRequiresComptime(field_ty)) continue;
if (try sema.typeHasRuntimeBits(field_ty)) {
const field_align = try sema.structFieldAlignment(
struct_type.fieldAlign(ip, i),
field_ty,
struct_type.layout,
);
result = result.max(field_align);
}
}
struct_type.flagsPtr(ip).alignment = result;
return result;
}
fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
const mod = sema.mod;
const ip = &mod.intern_pool;
const struct_type = mod.typeToStruct(ty) orelse return;
@ -34290,6 +34335,8 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
if (struct_type.haveLayout(ip))
return;
try sema.resolveTypeFields(ty);
if (struct_type.layout == .Packed) {
try semaBackingIntType(mod, struct_type);
return;

View File

@ -201,7 +201,7 @@ pub const Type = struct {
info.flags.alignment
else
info.child.toType().abiAlignment(mod);
try writer.print("align({d}", .{alignment});
try writer.print("align({d}", .{alignment.toByteUnits(0)});
if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
try writer.print(":{d}:{d}", .{
@ -992,30 +992,22 @@ pub const Type = struct {
},
.eager => {},
}
assert(struct_type.backingIntType(ip).* != .none);
return .{ .scalar = struct_type.backingIntType(ip).toType().abiAlignment(mod) };
}
const flags = struct_type.flagsPtr(ip).*;
if (flags.layout_resolved) return .{ .scalar = flags.alignment };
if (flags.alignment != .none) return .{ .scalar = flags.alignment };
switch (strat) {
.eager => unreachable, // struct layout not resolved
.sema => |sema| {
if (flags.field_types_wip) {
// We'll guess "pointer-aligned", if the struct has an
// underaligned pointer field then some allocations
// might require explicit alignment.
return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
}
try sema.resolveTypeLayout(ty);
return .{ .scalar = struct_type.flagsPtr(ip).alignment };
return switch (strat) {
.eager => unreachable, // struct alignment not resolved
.sema => |sema| .{
.scalar = try sema.resolveStructAlignment(ty.toIntern(), struct_type),
},
.lazy => return .{ .val = (try mod.intern(.{ .int = .{
.lazy => .{ .val = (try mod.intern(.{ .int = .{
.ty = .comptime_int_type,
.storage = .{ .lazy_align = ty.toIntern() },
} })).toValue() },
}
};
},
.anon_struct_type => |tuple| {
var big_align: Alignment = .none;