diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 5dc269028e0fd..79621d230ccfb 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -180,10 +180,13 @@ class RecursiveTypeProperties { /// they have a type variable originator. SolverAllocated = 0x8000, - /// This type contains a concrete pack. - HasConcretePack = 0x10000, + /// Contains a PackType. + HasPack = 0x10000, - Last_Property = HasConcretePack + /// Contains a PackArchetypeType. + HasPackArchetype = 0x20000, + + Last_Property = HasPackArchetype }; enum { BitWidth = countBitsUsed(Property::Last_Property) }; @@ -259,7 +262,9 @@ class RecursiveTypeProperties { bool hasParameterPack() const { return Bits & HasParameterPack; } - bool hasConcretePack() const { return Bits & HasConcretePack; } + bool hasPack() const { return Bits & HasPack; } + + bool hasPackArchetype() const { return Bits & HasPackArchetype; } /// Does a type with these properties structurally contain a /// parameterized existential type? @@ -419,12 +424,12 @@ class alignas(1 << TypeAlignInBits) TypeBase NumProtocols : 16 ); - SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+30, + SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+29, /// Type variable options. Options : 7, : NumPadBits, /// The unique number assigned to this type variable. - ID : 30 + ID : 29 ); SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+4+1+2+1+1, @@ -687,16 +692,26 @@ class alignas(1 << TypeAlignInBits) TypeBase return getRecursiveProperties().hasLocalArchetype(); } + /// Whether the type contains a generic parameter declared as a parameter + /// pack. bool hasParameterPack() const { return getRecursiveProperties().hasParameterPack(); } - bool hasConcretePack() const { - return getRecursiveProperties().hasConcretePack(); + /// Whether the type contains a PackType. + bool hasPack() const { + return getRecursiveProperties().hasPack(); } - /// Whether the type has some flavor of pack. - bool hasPack() const { return hasParameterPack() || hasConcretePack(); } + /// Whether the type contains a PackArchetypeType. + bool hasPackArchetype() const { + return getRecursiveProperties().hasPackArchetype(); + } + + /// Whether the type has any flavor of pack. + bool hasAnyPack() const { + return hasParameterPack() || hasPack() || hasPackArchetype(); + } /// Determine whether the type involves a parameterized existential type. bool hasParameterizedExistential() const { diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index 7be9bd084e973..36ebad88ddccb 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -352,12 +352,15 @@ class SILType { /// pack. bool hasParameterPack() const { return getASTType()->hasParameterPack(); } - /// Whether the type contains a concrete pack. - bool hasConcretePack() const { return getASTType()->hasConcretePack(); } - - /// Whether the type contains some flavor of pack. + /// Whether the type contains a PackType. bool hasPack() const { return getASTType()->hasPack(); } + /// Whether the type contains a PackArchetypeType. + bool hasPackArchetype() const { return getASTType()->hasPackArchetype(); } + + /// Whether the type contains any flavor of pack. + bool hasAnyPack() const { return getASTType()->hasAnyPack(); } + /// True if the type is an empty tuple or an empty struct or a tuple or /// struct containing only empty types. bool isEmpty(const SILFunction &F) const; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 6f5db8ef1debb..44e5b43b9cc39 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3404,7 +3404,7 @@ CanPackType CanPackType::get(const ASTContext &C, } PackType *PackType::get(const ASTContext &C, ArrayRef elements) { - RecursiveTypeProperties properties = RecursiveTypeProperties::HasConcretePack; + RecursiveTypeProperties properties = RecursiveTypeProperties::HasPack; bool isCanonical = true; for (Type eltTy : elements) { assert(!eltTy->is() && @@ -3444,7 +3444,7 @@ void PackType::Profile(llvm::FoldingSetNodeID &ID, ArrayRef Elements) { CanSILPackType SILPackType::get(const ASTContext &C, ExtInfo info, ArrayRef elements) { - RecursiveTypeProperties properties = RecursiveTypeProperties::HasConcretePack; + RecursiveTypeProperties properties; for (CanType eltTy : elements) { assert(!isa(eltTy) && "Cannot have pack directly inside another pack"); @@ -4036,7 +4036,7 @@ isAnyFunctionTypeCanonical(ArrayRef params, static RecursiveTypeProperties getGenericFunctionRecursiveProperties(ArrayRef params, Type result) { - static_assert(RecursiveTypeProperties::BitWidth == 17, + static_assert(RecursiveTypeProperties::BitWidth == 18, "revisit this if you add new recursive type properties"); RecursiveTypeProperties properties; @@ -4677,7 +4677,7 @@ CanSILFunctionType SILFunctionType::get( void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); RecursiveTypeProperties properties; - static_assert(RecursiveTypeProperties::BitWidth == 17, + static_assert(RecursiveTypeProperties::BitWidth == 18, "revisit this if you add new recursive type properties"); for (auto ¶m : params) properties |= param.getInterfaceType()->getRecursiveProperties(); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index ccb64354851bf..341b3438d6b20 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3703,8 +3703,9 @@ PackArchetypeType::PackArchetypeType( ArrayRef ConformsTo, Type Superclass, LayoutConstraint Layout, PackShape Shape) : ArchetypeType(TypeKind::PackArchetype, Ctx, - RecursiveTypeProperties::HasArchetype, InterfaceType, - ConformsTo, Superclass, Layout, GenericEnv) { + RecursiveTypeProperties::HasArchetype | + RecursiveTypeProperties::HasPackArchetype, + InterfaceType, ConformsTo, Superclass, Layout, GenericEnv) { assert(InterfaceType->isParameterPack()); *getTrailingObjects() = Shape; } diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 27fbc0e993588..57ee37bb8bb3b 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -2645,6 +2645,10 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) { llvm::report_fatal_error( "Instruction resulted in on-stack pack metadata emission but no " "cleanup instructions were added"); + // The markers which indicate where on-stack pack metadata should be + // deallocated were not inserted for I. To fix this, add I's opcode to + // SILInstruction::mayRequirePackMetadata subject to the appropriate + // checks. } } #endif diff --git a/lib/IRGen/PackMetadataMarkerInserter.cpp b/lib/IRGen/PackMetadataMarkerInserter.cpp index 33cd533cfaa24..e146bf6519c5d 100644 --- a/lib/IRGen/PackMetadataMarkerInserter.cpp +++ b/lib/IRGen/PackMetadataMarkerInserter.cpp @@ -91,7 +91,7 @@ Inserter::shouldInsertMarkersForInstruction(SILInstruction *inst) { BuiltinValueKind::StartAsyncLetWithLocalBuffer || bi->getBuiltinKind() == BuiltinValueKind::StartAsyncLet) return Inserter::FindResult::Unhandleable; - return Inserter::FindResult::None; + LLVM_FALLTHROUGH; } default: return inst->mayRequirePackMetadata() ? FindResult::Some : FindResult::None; diff --git a/lib/SIL/IR/SILInstruction.cpp b/lib/SIL/IR/SILInstruction.cpp index cc1df3687affb..fc834ce4b12df 100644 --- a/lib/SIL/IR/SILInstruction.cpp +++ b/lib/SIL/IR/SILInstruction.cpp @@ -1305,33 +1305,64 @@ bool SILInstruction::mayRequirePackMetadata() const { case SILInstructionKind::TryApplyInst: { // Check the function type for packs. auto apply = ApplySite::isa(const_cast(this)); - if (apply.getCallee()->getType().hasPack()) + if (apply.getCallee()->getType().hasAnyPack()) return true; // Check the substituted types for packs. for (auto ty : apply.getSubstitutionMap().getReplacementTypes()) { - if (ty->hasPack()) + if (ty->hasAnyPack()) return true; } return false; } - case SILInstructionKind::DebugValueInst: { - auto *dvi = cast(this); - return dvi->getOperand()->getType().hasPack(); + case SILInstructionKind::ClassMethodInst: + case SILInstructionKind::DebugValueInst: + case SILInstructionKind::DestroyAddrInst: + case SILInstructionKind::DestroyValueInst: + // Unary instructions. + { + return getOperand(0)->getType().hasAnyPack(); + } + case SILInstructionKind::AllocStackInst: { + auto *asi = cast(this); + return asi->getType().hasAnyPack(); } case SILInstructionKind::MetatypeInst: { auto *mi = cast(this); - return mi->getType().hasPack(); - } - case SILInstructionKind::ClassMethodInst: { - auto *cmi = cast(this); - return cmi->getOperand()->getType().hasPack(); + return mi->getType().hasAnyPack(); } case SILInstructionKind::WitnessMethodInst: { auto *wmi = cast(this); auto ty = wmi->getLookupType(); - return ty->hasPack(); + return ty->hasAnyPack(); } default: + // Instructions that deallocate stack must not result in pack metadata + // materialization. If they did there would be no way to create the pack + // metadata on stack. + if (isDeallocatingStack()) + return false; + + // Terminators that exit the function must not result in pack metadata + // materialization. + auto *ti = dyn_cast(this); + if (ti && ti->isFunctionExiting()) + return false; + + // Check results and operands for packs. If a pack appears, lowering the + // instruction might result in pack metadata emission. + for (auto result : getResults()) { + if (result->getType().hasAnyPack()) + return true; + } + for (auto operandTy : getOperandTypes()) { + if (operandTy.hasAnyPack()) + return true; + } + for (auto &tdo : getTypeDependentOperands()) { + if (tdo.get()->getType().hasAnyPack()) + return true; + } + return false; } } diff --git a/test/IRGen/pack_marker_insertion.swift b/test/IRGen/pack_marker_insertion.swift new file mode 100644 index 0000000000000..6e5c2f7e3ede4 --- /dev/null +++ b/test/IRGen/pack_marker_insertion.swift @@ -0,0 +1,6 @@ +// RUN: %target-swift-frontend -emit-ir %s + +// Verify that we don't hit the `Instruction missing on-stack pack metadata cleanups!` assertion. + +// For alloc_stacks of tuples featuring a pack. +public func tupleExpansionWithMemberType(seqs: (repeat each T), elts: (repeat (each T).Element)) {} diff --git a/test/IRGen/pack_metadata_marker_inserter.sil b/test/IRGen/pack_metadata_marker_inserter.sil index a8eefd5e2af3f..80c31cea2fb34 100644 --- a/test/IRGen/pack_metadata_marker_inserter.sil +++ b/test/IRGen/pack_metadata_marker_inserter.sil @@ -22,6 +22,9 @@ struct S1 {} struct S2 {} struct S3 {} +struct GVT : Error { +} + struct GV { var tu: (repeat each T) } @@ -145,6 +148,16 @@ entry: return %retval : $() } +// CHECK-SIL-LABEL: sil @return_variadic : {{.*}} { +// CHECK-SIL: [[RETVAL:%[^,]+]] = struct +// CHECK-SIL: return [[RETVAL]] +// CHECK-SIL-LABEL: } // end sil function 'return_variadic' +sil @return_variadic : $() -> GVT { +entry: + %retval = struct $GVT () + return %retval : $GVT +} + // ============================================================================= // FINISH: Instructions: Apply }} // ============================================================================= diff --git a/test/IRGen/pack_metadata_marker_inserter_no_ir.sil b/test/IRGen/pack_metadata_marker_inserter_no_ir.sil new file mode 100644 index 0000000000000..2e0224efa77de --- /dev/null +++ b/test/IRGen/pack_metadata_marker_inserter_no_ir.sil @@ -0,0 +1,23 @@ +// RUN: %target-sil-opt -enable-sil-verify-all %s -pack-metadata-marker-inserter -enable-pack-metadata-stack-promotion=true | %FileCheck %s --check-prefixes CHECK-SIL + +// REQUIRES: asserts + +sil_stage lowered + +import Builtin + +protocol Error {} + +struct GVT { +} + +// CHECK-SIL-LABEL: sil @throw_variadic : {{.*}} { +// CHECK-SIL: [[ERROR:%[^,]+]] = struct +// CHECK-SIL: throw [[ERROR]] +// CHECK-SIL-LABEL: } // end sil function 'throw_variadic' +sil @throw_variadic : $() -> ((), @error GVT) { +entry: + %retval = struct $GVT () + throw %retval : $GVT +} + diff --git a/test/IRGen/rdar112792831.swift b/test/IRGen/rdar112792831.swift new file mode 100644 index 0000000000000..dcbb0c6a72b72 --- /dev/null +++ b/test/IRGen/rdar112792831.swift @@ -0,0 +1,41 @@ +// RUN: %target-swift-frontend -emit-ir -O %s + +@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) +public struct Predicate { + var x: Any? = nil + public func evaluate(_: repeat each Input) -> Bool { return false } +} + +public struct PredicateBindings { +} + +@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) +public protocol PredicateExpression { + associatedtype Output + + func evaluate(_ bindings: PredicateBindings) throws -> Output +} + +@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) +public struct PredicateEvaluate< + Condition : PredicateExpression, + each Input : PredicateExpression +> +where + Condition.Output == Predicate +{ + + public typealias Output = Bool + + public let predicate: Condition + public let input: (repeat each Input) + + public init(predicate: Condition, input: repeat each Input) { + self.predicate = predicate + self.input = (repeat each input) + } + + public func evaluate(_ bindings: PredicateBindings) throws -> Output { + try predicate.evaluate(bindings).evaluate(repeat (each input).evaluate(bindings)) + } +}