@@ -5403,10 +5403,9 @@ static const llvm::StringMap<std::vector<int>> STLConditionalParams{
54035403
54045404template <typename Kind>
54055405static bool checkConditionalParams (
5406- clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
5406+ const clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
54075407 const std::vector<int > &STLParams, std::set<StringRef> &conditionalParams,
5408- std::function<void (const clang::Type *)> &maybePushToStack) {
5409- HeaderLoc loc{recordDecl->getLocation ()};
5408+ llvm::function_ref<void (const clang::Type *)> maybePushToStack) {
54105409 bool foundErrors = false ;
54115410 auto specDecl = cast<clang::ClassTemplateSpecializationDecl>(recordDecl);
54125411 SmallVector<std::pair<unsigned , StringRef>, 4 > argumentsToCheck;
@@ -5437,7 +5436,8 @@ static bool checkConditionalParams(
54375436 for (auto nonPackArg : nonPackArgs) {
54385437 if (nonPackArg.getKind () != clang::TemplateArgument::Type) {
54395438 if (impl)
5440- impl->diagnose (loc, diag::type_template_parameter_expected,
5439+ impl->diagnose (HeaderLoc (recordDecl->getLocation ()),
5440+ diag::type_template_parameter_expected,
54415441 argToCheck.second );
54425442 foundErrors = true ;
54435443 } else {
@@ -5448,7 +5448,7 @@ static bool checkConditionalParams(
54485448 }
54495449 if (hasInjectedSTLAnnotation)
54505450 break ;
5451- clang::DeclContext *dc = specDecl;
5451+ const clang::DeclContext *dc = specDecl;
54525452 specDecl = nullptr ;
54535453 while ((dc = dc->getParent ())) {
54545454 specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(dc);
@@ -5495,19 +5495,33 @@ getConditionalCopyableAttrParams(const clang::RecordDecl *decl) {
54955495CxxEscapability
54965496ClangTypeEscapability::evaluate (Evaluator &evaluator,
54975497 EscapabilityLookupDescriptor desc) const {
5498+
5499+ // Escapability inference rules:
5500+ // - array and vector types have the same escapability as their element type
5501+ // - pointer and reference types are currently imported as escapable
5502+ // (importing them as non-escapable broke backward compatibility)
5503+ // - a record type is escapable or non-escapable if it is explicitly annotated
5504+ // as such
5505+ // - a record type is escapable if it is annotated with SWIFT_ESCAPABLE_IF()
5506+ // and none of the annotation arguments are non-escapable
5507+ // - in all other cases, the record has unknown escapability (e.g. no
5508+ // escapability annotations, malformed escapability annotations)
5509+
54985510 bool hasUnknown = false ;
54995511 auto desugared = desc.type ->getUnqualifiedDesugaredType ();
55005512 if (const auto *recordType = desugared->getAs <clang::RecordType>()) {
55015513 auto recordDecl = recordType->getDecl ();
5514+ // If the root type has a SWIFT_ESCAPABLE annotation, we import the type as
5515+ // Escapable without entering the loop
55025516 if (hasEscapableAttr (recordDecl))
55035517 return CxxEscapability::Escapable;
55045518 }
55055519
55065520 llvm::SmallVector<const clang::Type *, 4 > stack;
5507- // Keep track of Decls we've seen to avoid cycles
5521+ // Keep track of Types we've seen to avoid cycles
55085522 llvm::SmallDenseSet<const clang::Type *, 4 > seen;
55095523
5510- std::function maybePushToStack = [&](const clang::Type *type) {
5524+ auto maybePushToStack = [&](const clang::Type *type) {
55115525 auto desugared = type->getUnqualifiedDesugaredType ();
55125526 if (seen.insert (desugared).second )
55135527 stack.push_back (desugared);
@@ -5545,6 +5559,10 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55455559
55465560 continue ;
55475561 }
5562+ // The `annotationOnly` flag used to control which types we infered
5563+ // escapability for. Currently, this flag is always set to true, meaning
5564+ // that any type without an annotation (CxxRecordDecls, aggregates, decls
5565+ // lacking definition, etc.) will raise `hasUnknown`.
55485566 if (desc.annotationOnly ) {
55495567 hasUnknown = true ;
55505568 continue ;
@@ -5560,8 +5578,7 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55605578 maybePushToStack (field->getType ()->getUnqualifiedDesugaredType ());
55615579 continue ;
55625580 }
5563- }
5564- if (type->isArrayType ()) {
5581+ } else if (type->isArrayType ()) {
55655582 auto elemTy = cast<clang::ArrayType>(type)
55665583 ->getElementType ()
55675584 ->getUnqualifiedDesugaredType ();
@@ -8467,21 +8484,25 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
84678484 // We assume a type can be imported as Copyable unless:
84688485 // - There's no copy constructor
84698486 // - The type has a SWIFT_NONCOPYABLE annotation
8470- // - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of T is ~Copyable
8471- // - It is one of the STL types in `STLConditionalParams`
8487+ // - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of
8488+ // T is ~Copyable
8489+ // - It is one of the STL types in `STLConditionalParams`, and at least one of
8490+ // its revelant types is ~Copyable
84728491
84738492 const auto *type = desc.type ->getUnqualifiedDesugaredType ();
84748493 auto *importerImpl = desc.importerImpl ;
84758494
8476- llvm::SmallVector<clang::RecordDecl *, 4 > stack;
8495+ bool hasUnknown = false ;
8496+ llvm::SmallVector<const clang::RecordDecl *, 4 > stack;
84778497 // Keep track of Decls we've seen to avoid cycles
8478- llvm::SmallDenseSet<clang::RecordDecl *, 4 > seen;
8498+ llvm::SmallDenseSet<const clang::RecordDecl *, 4 > seen;
84798499
8480- std::function maybePushToStack = [&](const clang::Type *type) {
8481- auto recordDecl = type->getAsRecordDecl ();
8482- if (!recordDecl )
8500+ auto maybePushToStack = [&](const clang::Type *type) {
8501+ auto recordType = type->getAs <clang::RecordType> ();
8502+ if (!recordType )
84838503 return ;
84848504
8505+ auto recordDecl = recordType->getDecl ();
84858506 if (seen.insert (recordDecl).second ) {
84868507 // When a reference type is copied, the pointer’s value is copied rather
84878508 // than the object’s storage. This means reference types can be imported
@@ -8502,7 +8523,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85028523
85038524 maybePushToStack (type);
85048525 while (!stack.empty ()) {
8505- clang::RecordDecl *recordDecl = stack.back ();
8526+ const clang::RecordDecl *recordDecl = stack.back ();
85068527 stack.pop_back ();
85078528
85088529 if (!hasNonCopyableAttr (recordDecl)) {
@@ -8516,22 +8537,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85168537 auto conditionalParams = getConditionalCopyableAttrParams (recordDecl);
85178538
85188539 if (!STLParams.empty () || !conditionalParams.empty ()) {
8519- HeaderLoc loc{recordDecl->getLocation ()};
8520- std::function checkArgValueSemantics =
8521- [&](clang::TemplateArgument &arg,
8522- StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8523- if (arg.getKind () != clang::TemplateArgument::Type) {
8524- if (importerImpl)
8525- importerImpl->diagnose (
8526- loc, diag::type_template_parameter_expected, argToCheck);
8527- return std::nullopt ;
8528- }
8529- maybePushToStack (arg.getAsType ()->getUnqualifiedDesugaredType ());
8530- // FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request
8531- return std::nullopt ;
8532- };
8533-
8534- checkConditionalParams<CxxValueSemanticsKind>(
8540+ hasUnknown &= checkConditionalParams<CxxValueSemanticsKind>(
85358541 recordDecl, importerImpl, STLParams, conditionalParams,
85368542 maybePushToStack);
85378543
@@ -8546,7 +8552,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85468552 }
85478553
85488554 const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8549- if (!cxxRecordDecl || !cxxRecordDecl ->isCompleteDefinition ()) {
8555+ if (!cxxRecordDecl || !recordDecl ->isCompleteDefinition ()) {
85508556 if (hasNonCopyableAttr (recordDecl))
85518557 return CxxValueSemanticsKind::MoveOnly;
85528558 continue ;
@@ -8560,9 +8566,11 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85608566 (!isCopyable && !isMovable)) {
85618567
85628568 if (hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl))
8563- return CxxValueSemanticsKind::UnavailableConstructors;
8564-
8565- return CxxValueSemanticsKind::MissingLifetimeOperation;
8569+ importerImpl->addImportDiagnostic (
8570+ cxxRecordDecl, Diagnostic (diag::record_unsupported_default_args),
8571+ cxxRecordDecl->getLocation ());
8572+ hasUnknown = true ;
8573+ continue ;
85668574 }
85678575
85688576 if (hasNonCopyableAttr (cxxRecordDecl) && isMovable)
@@ -8577,7 +8585,8 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85778585 llvm_unreachable (" Could not classify C++ type." );
85788586 }
85798587
8580- return CxxValueSemanticsKind::Copyable;
8588+ return hasUnknown ? CxxValueSemanticsKind::Unknown
8589+ : CxxValueSemanticsKind::Copyable;
85818590}
85828591
85838592void swift::simple_display (llvm::raw_ostream &out,
0 commit comments