diff --git a/src/Sema.zig b/src/Sema.zig index 97c9217a5e..310058a421 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -35054,7 +35054,7 @@ pub fn resolveUnionAlignment( union_type.setAlignment(ip, max_align); } -/// This logic must be kept in sync with `Zcu.getUnionLayout`. +/// This logic must be kept in sync with `Type.getUnionLayout`. pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { const pt = sema.pt; const ip = &pt.zcu.intern_pool; @@ -35090,6 +35090,14 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { const field_ty: Type = .fromInterned(union_type.field_types.get(ip)[field_index]); if (field_ty.isNoReturn(pt.zcu)) continue; + // We need to call `hasRuntimeBits` before calling `abiSize` to prevent reachable `unreachable`s, + // but `hasRuntimeBits` only resolves field types and so may infinite recurse on a layout wip type, + // so we must resolve the layout manually first, instead of waiting for `abiSize` to do it for us. + // This is arguably just hacking around bugs in both `abiSize` for not allowing arbitrary types to + // be queried, enabling failures to be handled with the emission of a compile error, and also in + // `hasRuntimeBits` for ever being able to infinite recurse in the first place. + try field_ty.resolveLayout(pt); + if (try field_ty.hasRuntimeBitsSema(pt)) { max_size = @max(max_size, field_ty.abiSizeSema(pt) catch |err| switch (err) { error.AnalysisFail => { diff --git a/src/Type.zig b/src/Type.zig index 64b389cf5f..eafdd65531 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -3915,29 +3915,30 @@ fn resolveUnionInner( pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout { const ip = &zcu.intern_pool; assert(loaded_union.haveLayout(ip)); - var most_aligned_field: u32 = undefined; - var most_aligned_field_size: u64 = undefined; - var biggest_field: u32 = undefined; + var most_aligned_field: u32 = 0; + var most_aligned_field_align: InternPool.Alignment = .@"1"; + var most_aligned_field_size: u64 = 0; + var biggest_field: u32 = 0; var payload_size: u64 = 0; var payload_align: InternPool.Alignment = .@"1"; - for (loaded_union.field_types.get(ip), 0..) |field_ty, field_index| { - if (Type.fromInterned(field_ty).isNoReturn(zcu)) continue; + for (loaded_union.field_types.get(ip), 0..) |field_ty_ip_index, field_index| { + const field_ty: Type = .fromInterned(field_ty_ip_index); + if (field_ty.isNoReturn(zcu)) continue; const explicit_align = loaded_union.fieldAlign(ip, field_index); const field_align = if (explicit_align != .none) explicit_align else - Type.fromInterned(field_ty).abiAlignment(zcu); - if (Type.fromInterned(field_ty).hasRuntimeBits(zcu)) { - const field_size = Type.fromInterned(field_ty).abiSize(zcu); - if (field_size > payload_size) { - payload_size = field_size; - biggest_field = @intCast(field_index); - } - if (field_align.compare(.gte, payload_align)) { - most_aligned_field = @intCast(field_index); - most_aligned_field_size = field_size; - } + field_ty.abiAlignment(zcu); + const field_size = field_ty.abiSize(zcu); + if (field_size > payload_size) { + payload_size = field_size; + biggest_field = @intCast(field_index); + } + if (field_size > 0 and field_align.compare(.gte, most_aligned_field_align)) { + most_aligned_field = @intCast(field_index); + most_aligned_field_align = field_align; + most_aligned_field_size = field_size; } payload_align = payload_align.max(field_align); }