Commit 746137034e
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 => {
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);
}