Commit 5ea3de55c4

Andrew Kelley <andrew@ziglang.org>
2023-09-21 01:44:10
Sema: fix dependency loop regression on struct field alignment
1 parent 2671aa9
Changed files (2)
src/Sema.zig
@@ -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;
src/type.zig
@@ -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;