authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-20 16:44:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-21 14:48:40-07:00
log5ea3de55c4ca89b1f9fd95e40e6dd17cc89efe23
treeec6fe5bed28ae7e691cee88f32c93402fc7124cd
parent2671aa9058b3dcff147ef01dcf3876b0bb231673

Sema: fix dependency loop regression on struct field alignment


2 files changed, 57 insertions(+), 18 deletions(-)

src/Sema.zig+49-2
...@@ -34280,9 +34280,54 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -34280,9 +34280,54 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
34280 }34280 }
34281}34281}
3428234282
34283fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {34283/// Resolve a struct's alignment only without triggering resolution of its layout.
34284 try sema.resolveTypeFields(ty);34284/// Asserts that the alignment is not yet resolved and the layout is non-packed.
34285pub fn resolveStructAlignment(
34286 sema: *Sema,
34287 ty: InternPool.Index,
34288 struct_type: InternPool.Key.StructType,
34289) CompileError!Alignment {
34290 const mod = sema.mod;
34291 const ip = &mod.intern_pool;
34292 const target = mod.getTarget();
34293
34294 assert(struct_type.flagsPtr(ip).alignment == .none);
34295 assert(struct_type.layout != .Packed);
34296
34297 if (struct_type.flagsPtr(ip).field_types_wip) {
34298 // We'll guess "pointer-aligned", if the struct has an
34299 // underaligned pointer field then some allocations
34300 // might require explicit alignment.
34301 //TODO write this bit and emit an error later if incorrect
34302 //struct_type.flagsPtr(ip).assumed_pointer_aligned = true;
34303 const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
34304 struct_type.flagsPtr(ip).alignment = result;
34305 return result;
34306 }
34307
34308 try sema.resolveTypeFieldsStruct(ty, struct_type);
34309
34310 var result: Alignment = .@"1";
3428534311
34312 for (0..struct_type.field_types.len) |i| {
34313 if (struct_type.fieldIsComptime(ip, i)) continue;
34314 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 }
34324 }
34325
34326 struct_type.flagsPtr(ip).alignment = result;
34327 return result;
34328}
34329
34330fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
34286 const mod = sema.mod;34331 const mod = sema.mod;
34287 const ip = &mod.intern_pool;34332 const ip = &mod.intern_pool;
34288 const struct_type = mod.typeToStruct(ty) orelse return;34333 const struct_type = mod.typeToStruct(ty) orelse return;
...@@ -34290,6 +34335,8 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -34290,6 +34335,8 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
34290 if (struct_type.haveLayout(ip))34335 if (struct_type.haveLayout(ip))
34291 return;34336 return;
3429234337
34338 try sema.resolveTypeFields(ty);
34339
34293 if (struct_type.layout == .Packed) {34340 if (struct_type.layout == .Packed) {
34294 try semaBackingIntType(mod, struct_type);34341 try semaBackingIntType(mod, struct_type);
34295 return;34342 return;
src/type.zig+8-16
...@@ -201,7 +201,7 @@ pub const Type = struct {...@@ -201,7 +201,7 @@ pub const Type = struct {
201 info.flags.alignment201 info.flags.alignment
202 else202 else
203 info.child.toType().abiAlignment(mod);203 info.child.toType().abiAlignment(mod);
204 try writer.print("align({d}", .{alignment});204 try writer.print("align({d}", .{alignment.toByteUnits(0)});
205205
206 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {206 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
207 try writer.print(":{d}:{d}", .{207 try writer.print(":{d}:{d}", .{
...@@ -992,30 +992,22 @@ pub const Type = struct {...@@ -992,30 +992,22 @@ pub const Type = struct {
992 },992 },
993 .eager => {},993 .eager => {},
994 }994 }
995 assert(struct_type.backingIntType(ip).* != .none);
996 return .{ .scalar = struct_type.backingIntType(ip).toType().abiAlignment(mod) };995 return .{ .scalar = struct_type.backingIntType(ip).toType().abiAlignment(mod) };
997 }996 }
998997
999 const flags = struct_type.flagsPtr(ip).*;998 const flags = struct_type.flagsPtr(ip).*;
1000 if (flags.layout_resolved) return .{ .scalar = flags.alignment };999 if (flags.alignment != .none) return .{ .scalar = flags.alignment };
10011000
1002 switch (strat) {1001 return switch (strat) {
1003 .eager => unreachable, // struct layout not resolved1002 .eager => unreachable, // struct alignment not resolved
1004 .sema => |sema| {1003 .sema => |sema| .{
1005 if (flags.field_types_wip) {1004 .scalar = try sema.resolveStructAlignment(ty.toIntern(), struct_type),
1006 // We'll guess "pointer-aligned", if the struct has an
1007 // underaligned pointer field then some allocations
1008 // might require explicit alignment.
1009 return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
1010 }
1011 try sema.resolveTypeLayout(ty);
1012 return .{ .scalar = struct_type.flagsPtr(ip).alignment };
1013 },1005 },
1014 .lazy => return .{ .val = (try mod.intern(.{ .int = .{1006 .lazy => .{ .val = (try mod.intern(.{ .int = .{
1015 .ty = .comptime_int_type,1007 .ty = .comptime_int_type,
1016 .storage = .{ .lazy_align = ty.toIntern() },1008 .storage = .{ .lazy_align = ty.toIntern() },
1017 } })).toValue() },1009 } })).toValue() },
1018 }1010 };
1019 },1011 },
1020 .anon_struct_type => |tuple| {1012 .anon_struct_type => |tuple| {
1021 var big_align: Alignment = .none;1013 var big_align: Alignment = .none;