@@ -5382,10 +5382,9 @@ static const llvm::StringMap<std::vector<int>> STLConditionalParams{
53825382
53835383template <typename Kind>
53845384static bool checkConditionalParams (
5385- clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
5385+ const clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
53865386 const std::vector<int > &STLParams, std::set<StringRef> &conditionalParams,
5387- std::function<void (const clang::Type *)> &maybePushToStack) {
5388- HeaderLoc loc{recordDecl->getLocation ()};
5387+ llvm::function_ref<void (const clang::Type *)> maybePushToStack) {
53895388 bool foundErrors = false ;
53905389 auto specDecl = cast<clang::ClassTemplateSpecializationDecl>(recordDecl);
53915390 SmallVector<std::pair<unsigned , StringRef>, 4 > argumentsToCheck;
@@ -5416,7 +5415,8 @@ static bool checkConditionalParams(
54165415 for (auto nonPackArg : nonPackArgs) {
54175416 if (nonPackArg.getKind () != clang::TemplateArgument::Type) {
54185417 if (impl)
5419- impl->diagnose (loc, diag::type_template_parameter_expected,
5418+ impl->diagnose (HeaderLoc (recordDecl->getLocation ()),
5419+ diag::type_template_parameter_expected,
54205420 argToCheck.second );
54215421 foundErrors = true ;
54225422 } else {
@@ -5427,7 +5427,7 @@ static bool checkConditionalParams(
54275427 }
54285428 if (hasInjectedSTLAnnotation)
54295429 break ;
5430- clang::DeclContext *dc = specDecl;
5430+ const clang::DeclContext *dc = specDecl;
54315431 specDecl = nullptr ;
54325432 while ((dc = dc->getParent ())) {
54335433 specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(dc);
@@ -5474,19 +5474,33 @@ getConditionalCopyableAttrParams(const clang::RecordDecl *decl) {
54745474CxxEscapability
54755475ClangTypeEscapability::evaluate (Evaluator &evaluator,
54765476 EscapabilityLookupDescriptor desc) const {
5477+
5478+ // Escapability inference rules:
5479+ // - array and vector types have the same escapability as their element type
5480+ // - pointer and reference types are currently imported as escapable
5481+ // (importing them as non-escapable broke backward compatibility)
5482+ // - a record type is escapable or non-escapable if it is explicitly annotated
5483+ // as such
5484+ // - a record type is escapable if it is annotated with SWIFT_ESCAPABLE_IF()
5485+ // and none of the annotation arguments are non-escapable
5486+ // - in all other cases, the record has unknown escapability (e.g. no
5487+ // escapability annotations, malformed escapability annotations)
5488+
54775489 bool hasUnknown = false ;
54785490 auto desugared = desc.type ->getUnqualifiedDesugaredType ();
54795491 if (const auto *recordType = desugared->getAs <clang::RecordType>()) {
54805492 auto recordDecl = recordType->getDecl ();
5493+ // If the root type has a SWIFT_ESCAPABLE annotation, we import the type as
5494+ // Escapable without entering the loop
54815495 if (hasEscapableAttr (recordDecl))
54825496 return CxxEscapability::Escapable;
54835497 }
54845498
54855499 llvm::SmallVector<const clang::Type *, 4 > stack;
5486- // Keep track of Decls we've seen to avoid cycles
5500+ // Keep track of Types we've seen to avoid cycles
54875501 llvm::SmallDenseSet<const clang::Type *, 4 > seen;
54885502
5489- std::function maybePushToStack = [&](const clang::Type *type) {
5503+ auto maybePushToStack = [&](const clang::Type *type) {
54905504 auto desugared = type->getUnqualifiedDesugaredType ();
54915505 if (seen.insert (desugared).second )
54925506 stack.push_back (desugared);
@@ -5524,6 +5538,10 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55245538
55255539 continue ;
55265540 }
5541+ // The `annotationOnly` flag used to control which types we infered
5542+ // escapability for. Currently, this flag is always set to true, meaning
5543+ // that any type without an annotation (CxxRecordDecls, aggregates, decls
5544+ // lacking definition, etc.) will raise `hasUnknown`.
55275545 if (desc.annotationOnly ) {
55285546 hasUnknown = true ;
55295547 continue ;
@@ -5539,8 +5557,7 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55395557 maybePushToStack (field->getType ()->getUnqualifiedDesugaredType ());
55405558 continue ;
55415559 }
5542- }
5543- if (type->isArrayType ()) {
5560+ } else if (type->isArrayType ()) {
55445561 auto elemTy = cast<clang::ArrayType>(type)
55455562 ->getElementType ()
55465563 ->getUnqualifiedDesugaredType ();
@@ -8446,21 +8463,25 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
84468463 // We assume a type can be imported as Copyable unless:
84478464 // - There's no copy constructor
84488465 // - The type has a SWIFT_NONCOPYABLE annotation
8449- // - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of T is ~Copyable
8450- // - It is one of the STL types in `STLConditionalParams`
8466+ // - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of
8467+ // T is ~Copyable
8468+ // - It is one of the STL types in `STLConditionalParams`, and at least one of
8469+ // its revelant types is ~Copyable
84518470
84528471 const auto *type = desc.type ->getUnqualifiedDesugaredType ();
84538472 auto *importerImpl = desc.importerImpl ;
84548473
8455- llvm::SmallVector<clang::RecordDecl *, 4 > stack;
8474+ bool hasUnknown = false ;
8475+ llvm::SmallVector<const clang::RecordDecl *, 4 > stack;
84568476 // Keep track of Decls we've seen to avoid cycles
8457- llvm::SmallDenseSet<clang::RecordDecl *, 4 > seen;
8477+ llvm::SmallDenseSet<const clang::RecordDecl *, 4 > seen;
84588478
8459- std::function maybePushToStack = [&](const clang::Type *type) {
8460- auto recordDecl = type->getAsRecordDecl ();
8461- if (!recordDecl )
8479+ auto maybePushToStack = [&](const clang::Type *type) {
8480+ auto recordType = type->getAs <clang::RecordType> ();
8481+ if (!recordType )
84628482 return ;
84638483
8484+ auto recordDecl = recordType->getDecl ();
84648485 if (seen.insert (recordDecl).second ) {
84658486 // When a reference type is copied, the pointer’s value is copied rather
84668487 // than the object’s storage. This means reference types can be imported
@@ -8481,7 +8502,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
84818502
84828503 maybePushToStack (type);
84838504 while (!stack.empty ()) {
8484- clang::RecordDecl *recordDecl = stack.back ();
8505+ const clang::RecordDecl *recordDecl = stack.back ();
84858506 stack.pop_back ();
84868507
84878508 if (!hasNonCopyableAttr (recordDecl)) {
@@ -8495,22 +8516,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
84958516 auto conditionalParams = getConditionalCopyableAttrParams (recordDecl);
84968517
84978518 if (!STLParams.empty () || !conditionalParams.empty ()) {
8498- HeaderLoc loc{recordDecl->getLocation ()};
8499- std::function checkArgValueSemantics =
8500- [&](clang::TemplateArgument &arg,
8501- StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8502- if (arg.getKind () != clang::TemplateArgument::Type) {
8503- if (importerImpl)
8504- importerImpl->diagnose (
8505- loc, diag::type_template_parameter_expected, argToCheck);
8506- return std::nullopt ;
8507- }
8508- maybePushToStack (arg.getAsType ()->getUnqualifiedDesugaredType ());
8509- // FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request
8510- return std::nullopt ;
8511- };
8512-
8513- checkConditionalParams<CxxValueSemanticsKind>(
8519+ hasUnknown &= checkConditionalParams<CxxValueSemanticsKind>(
85148520 recordDecl, importerImpl, STLParams, conditionalParams,
85158521 maybePushToStack);
85168522
@@ -8525,7 +8531,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85258531 }
85268532
85278533 const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8528- if (!cxxRecordDecl || !cxxRecordDecl ->isCompleteDefinition ()) {
8534+ if (!cxxRecordDecl || !recordDecl ->isCompleteDefinition ()) {
85298535 if (hasNonCopyableAttr (recordDecl))
85308536 return CxxValueSemanticsKind::MoveOnly;
85318537 continue ;
@@ -8539,9 +8545,11 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85398545 (!isCopyable && !isMovable)) {
85408546
85418547 if (hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl))
8542- return CxxValueSemanticsKind::UnavailableConstructors;
8543-
8544- return CxxValueSemanticsKind::MissingLifetimeOperation;
8548+ importerImpl->addImportDiagnostic (
8549+ cxxRecordDecl, Diagnostic (diag::record_unsupported_default_args),
8550+ cxxRecordDecl->getLocation ());
8551+ hasUnknown = true ;
8552+ continue ;
85458553 }
85468554
85478555 if (hasNonCopyableAttr (cxxRecordDecl) && isMovable)
@@ -8556,7 +8564,8 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85568564 llvm_unreachable (" Could not classify C++ type." );
85578565 }
85588566
8559- return CxxValueSemanticsKind::Copyable;
8567+ return hasUnknown ? CxxValueSemanticsKind::Unknown
8568+ : CxxValueSemanticsKind::Copyable;
85608569}
85618570
85628571void swift::simple_display (llvm::raw_ostream &out,
0 commit comments