diff --git a/src/Module.zig b/src/Module.zig index 9bc61aa708..8fed3138e7 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1125,6 +1125,8 @@ pub const Union = struct { abi_align: Value, /// Returns the field alignment, assuming the union is not packed. + /// Keep implementation in sync with `Sema.unionFieldAlignment`. + /// Prefer to call that function instead of this one during Sema. pub fn normalAlignment(field: Field, target: Target) u32 { if (field.abi_align.tag() == .abi_align_default) { return field.ty.abiAlignment(target); diff --git a/src/Sema.zig b/src/Sema.zig index 4a8cd38dd4..7f32444774 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10402,7 +10402,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const union_field_fields = try fields_anon_decl.arena().create([3]Value); const alignment = switch (layout) { - .Auto, .Extern => field.normalAlignment(target), + .Auto, .Extern => try sema.unionFieldAlignment(block, src, field), .Packed => 0, }; @@ -17713,6 +17713,10 @@ fn resolveTypeLayout( .Optional => { var buf: Type.Payload.ElemType = undefined; const payload_ty = ty.optionalChild(&buf); + // In case of querying the ABI alignment of this optional, we will ask + // for hasRuntimeBits() of the payload type, so we need "requires comptime" + // to be known already before this function returns. + _ = try sema.typeRequiresComptime(block, src, payload_ty); return sema.resolveTypeLayout(block, src, payload_ty); }, .ErrorUnion => { @@ -17744,6 +17748,13 @@ fn resolveStructLayout( try sema.resolveTypeLayout(block, src, field.ty); } struct_obj.status = .have_layout; + + // In case of querying the ABI alignment of this struct, we will ask + // for hasRuntimeBits() of each field, so we need "requires comptime" + // to be known already before this function returns. + for (struct_obj.fields.values()) |field| { + _ = try sema.typeRequiresComptime(block, src, field.ty); + } } // otherwise it's a tuple; no need to resolve anything } @@ -19297,6 +19308,21 @@ fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32 return ty.abiAlignment(target); } +/// Not valid to call for packed unions. +/// Keep implementation in sync with `Module.Union.Field.normalAlignment`. +fn unionFieldAlignment( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + field: Module.Union.Field, +) !u32 { + if (field.abi_align.tag() == .abi_align_default) { + return sema.typeAbiAlignment(block, src, field.ty); + } else { + return @intCast(u32, field.abi_align.toUnsignedInt()); + } +} + /// Synchronize logic with `Type.isFnOrHasRuntimeBits`. pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { const fn_info = ty.fnInfo(); diff --git a/src/type.zig b/src/type.zig index 30f06a6296..a84a0f4520 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1619,10 +1619,6 @@ pub const Type = extern union { // These types have more than one possible value, so the result is the same as // asking whether they are comptime-only types. - // - // If we get an error that the comptimeOnly status hasn't been - // resolved yet, then we assume that there are runtime bits, - // just like we do for structs below .anyframe_T, .optional, .optional_single_mut_pointer, @@ -1636,7 +1632,7 @@ pub const Type = extern union { .const_slice, .mut_slice, .pointer, - => !(ty.comptimeOnly() catch return true), + => !ty.comptimeOnly(), .@"struct" => { const struct_obj = ty.castTag(.@"struct").?.data; @@ -1732,7 +1728,7 @@ pub const Type = extern union { .Inline => return false, else => {}, } - if (fn_info.return_type.comptimeOnly() catch unreachable) return false; + if (fn_info.return_type.comptimeOnly()) return false; return true; }, else => return ty.hasRuntimeBits(), @@ -3614,7 +3610,7 @@ pub const Type = extern union { /// During semantic analysis, instead call `Sema.typeRequiresComptime` which /// resolves field types rather than asserting they are already resolved. - pub fn comptimeOnly(ty: Type) error{StatusNotResolved}!bool { + pub fn comptimeOnly(ty: Type) bool { return switch (ty.tag()) { .u1, .u8, @@ -3735,7 +3731,7 @@ pub const Type = extern union { .tuple => { const tuple = ty.castTag(.tuple).?.data; for (tuple.types) |field_ty| { - if (try field_ty.comptimeOnly()) return true; + if (field_ty.comptimeOnly()) return true; } return false; }, @@ -3743,20 +3739,18 @@ pub const Type = extern union { .@"struct" => { const struct_obj = ty.castTag(.@"struct").?.data; switch (struct_obj.requires_comptime) { - .wip => unreachable, + .wip, .unknown => unreachable, // This function asserts types already resolved. .no => return false, .yes => return true, - .unknown => return error.StatusNotResolved, } }, .@"union", .union_tagged => { const union_obj = ty.cast(Type.Payload.Union).?.data; switch (union_obj.requires_comptime) { - .wip => unreachable, + .wip, .unknown => unreachable, // This function asserts types already resolved. .no => return false, .yes => return true, - .unknown => return error.StatusNotResolved, } },