Sema: fix union layout logic to match struct layout logic
This commit is contained in:
10
src/Sema.zig
10
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 => {
|
||||
|
||||
33
src/Type.zig
33
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user