@@ -8459,103 +8459,118 @@ CxxValueSemanticsKind
84598459CxxValueSemantics::evaluate (Evaluator &evaluator,
84608460 CxxValueSemanticsDescriptor desc) const {
84618461
8462- const auto *type = desc.type ;
8462+ // A C++ type can be imported to Swift as Copyable or ~Copyable.
8463+ // We assume a type can be imported as Copyable unless:
8464+ // - There's no copy constructor
8465+ // - The type has a SWIFT_NONCOPYABLE annotation
8466+ // - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of T is ~Copyable
8467+ // - It is one of the STL types in `STLConditionalParams`
8468+
8469+ const auto *type = desc.type ->getUnqualifiedDesugaredType ();
84638470 auto *importerImpl = desc.importerImpl ;
84648471
8465- auto desugared = type->getUnqualifiedDesugaredType ();
8466- const auto *recordType = desugared->getAs <clang::RecordType>();
8467- if (!recordType)
8468- return CxxValueSemanticsKind::Copyable;
8472+ llvm::SmallVector<clang::RecordDecl *, 4 > stack;
8473+ // Keep track of Decls we've seen to avoid cycles
8474+ llvm::SmallDenseSet<clang::RecordDecl *, 4 > seen;
84698475
8470- auto recordDecl = recordType->getDecl ();
8476+ auto maybePushToStack = [&](const clang::Type *type) {
8477+ auto recordDecl = type->getAsRecordDecl ();
8478+ if (!recordDecl)
8479+ return ;
84718480
8472- // When a reference type is copied, the pointer’s value is copied rather than
8473- // the object’s storage. This means reference types can be imported as
8474- // copyable to Swift, even when they are non-copyable in C++.
8475- if (recordHasReferenceSemantics (recordDecl, importerImpl))
8476- return CxxValueSemanticsKind::Copyable;
8481+ if (seen.insert (recordDecl).second ) {
8482+ // When a reference type is copied, the pointer’s value is copied rather
8483+ // than the object’s storage. This means reference types can be imported
8484+ // as copyable to Swift, even when they are non-copyable in C++.
8485+ if (recordHasReferenceSemantics (recordDecl, importerImpl))
8486+ return ;
84778487
8478- if (recordDecl->isInStdNamespace ()) {
8479- // Hack for a base type of std::optional from the Microsoft standard
8480- // library.
8481- if (recordDecl->getIdentifier () &&
8482- recordDecl->getName () == " _Optional_construct_base" )
8483- return CxxValueSemanticsKind::Copyable;
8484- }
8488+ if (recordDecl->isInStdNamespace ()) {
8489+ // Hack for a base type of std::optional from the Microsoft standard
8490+ // library.
8491+ if (recordDecl->getIdentifier () &&
8492+ recordDecl->getName () == " _Optional_construct_base" )
8493+ return ;
8494+ }
8495+ stack.push_back (recordDecl);
8496+ }
8497+ };
84858498
8486- if (!hasNonCopyableAttr (recordDecl)) {
8487- auto injectedStlAnnotation =
8488- recordDecl->isInStdNamespace ()
8489- ? STLConditionalParams.find (recordDecl->getName ())
8490- : STLConditionalParams.end ();
8491- auto STLParams = injectedStlAnnotation != STLConditionalParams.end ()
8492- ? injectedStlAnnotation->second
8493- : std::vector<int >();
8494- auto conditionalParams = getConditionalCopyableAttrParams (recordDecl);
8499+ maybePushToStack (type);
8500+ while (!stack.empty ()) {
8501+ clang::RecordDecl *recordDecl = stack.back ();
8502+ stack.pop_back ();
84958503
8496- if (!STLParams.empty () || !conditionalParams.empty ()) {
8497- HeaderLoc loc{recordDecl->getLocation ()};
8498- std::function checkArgValueSemantics =
8499- [&](clang::TemplateArgument &arg,
8500- StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8501- if (arg.getKind () != clang::TemplateArgument::Type && importerImpl) {
8502- importerImpl->diagnose (loc, diag::type_template_parameter_expected,
8503- argToCheck);
8504- return CxxValueSemanticsKind::Unknown;
8505- }
8504+ if (!hasNonCopyableAttr (recordDecl)) {
8505+ auto injectedStlAnnotation =
8506+ recordDecl->isInStdNamespace ()
8507+ ? STLConditionalParams.find (recordDecl->getName ())
8508+ : STLConditionalParams.end ();
8509+ auto STLParams = injectedStlAnnotation != STLConditionalParams.end ()
8510+ ? injectedStlAnnotation->second
8511+ : std::vector<int >();
8512+ auto conditionalParams = getConditionalCopyableAttrParams (recordDecl);
8513+
8514+ if (!STLParams.empty () || !conditionalParams.empty ()) {
8515+ HeaderLoc loc{recordDecl->getLocation ()};
8516+ std::function checkArgValueSemantics =
8517+ [&](clang::TemplateArgument &arg,
8518+ StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8519+ if (arg.getKind () != clang::TemplateArgument::Type) {
8520+ if (importerImpl)
8521+ importerImpl->diagnose (
8522+ loc, diag::type_template_parameter_expected, argToCheck);
8523+ return CxxValueSemanticsKind::Unknown;
8524+ }
8525+ maybePushToStack (arg.getAsType ()->getUnqualifiedDesugaredType ());
8526+ // FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request
8527+ return std::nullopt ;
8528+ };
85068529
8507- auto argValueSemantics = evaluateOrDefault (
8508- evaluator,
8509- CxxValueSemantics (
8510- {arg.getAsType ()->getUnqualifiedDesugaredType (), importerImpl}),
8511- {});
8512- if (argValueSemantics != CxxValueSemanticsKind::Copyable)
8513- return argValueSemantics;
8514- return std::nullopt ;
8515- };
8530+ checkConditionalParams<CxxValueSemanticsKind>(
8531+ recordDecl, STLParams, conditionalParams, checkArgValueSemantics);
85168532
8517- auto result = checkConditionalParams<CxxValueSemanticsKind>(
8518- recordDecl, STLParams, conditionalParams, checkArgValueSemantics);
8519- if (result.has_value ())
8520- return result.value ();
8533+ if (importerImpl)
8534+ for (auto name : conditionalParams)
8535+ importerImpl->diagnose (loc, diag::unknown_template_parameter, name);
85218536
8522- if (importerImpl)
8523- for ( auto name : conditionalParams)
8524- importerImpl-> diagnose (loc, diag::unknown_template_parameter, name);
8537+ continue ;
8538+ }
8539+ }
85258540
8526- return CxxValueSemanticsKind::Copyable;
8541+ const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8542+ if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition ()) {
8543+ if (hasNonCopyableAttr (recordDecl))
8544+ return CxxValueSemanticsKind::MoveOnly;
8545+ continue ;
85278546 }
8528- }
85298547
8530- const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8531- if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition ()) {
8532- if (hasNonCopyableAttr (recordDecl))
8533- return CxxValueSemanticsKind::MoveOnly;
8534- return CxxValueSemanticsKind::Copyable;
8535- }
8548+ bool isCopyable = !hasNonCopyableAttr (cxxRecordDecl) &&
8549+ hasCopyTypeOperations (cxxRecordDecl);
8550+ bool isMovable = hasMoveTypeOperations (cxxRecordDecl);
85368551
8537- bool isCopyable = !hasNonCopyableAttr (cxxRecordDecl) &&
8538- hasCopyTypeOperations (cxxRecordDecl);
8539- bool isMovable = hasMoveTypeOperations (cxxRecordDecl);
8552+ if (!hasDestroyTypeOperations (cxxRecordDecl) ||
8553+ (!isCopyable && !isMovable)) {
85408554
8541- if (!hasDestroyTypeOperations (cxxRecordDecl) || (!isCopyable && !isMovable)) {
8555+ if (hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl))
8556+ return CxxValueSemanticsKind::UnavailableConstructors;
85428557
8543- if ( hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl))
8544- return CxxValueSemanticsKind::UnavailableConstructors;
8558+ return CxxValueSemanticsKind::MissingLifetimeOperation;
8559+ }
85458560
8546- return CxxValueSemanticsKind::MissingLifetimeOperation;
8547- }
8561+ if ( hasNonCopyableAttr (cxxRecordDecl) && isMovable)
8562+ return CxxValueSemanticsKind::MoveOnly;
85488563
8549- if ( hasNonCopyableAttr (cxxRecordDecl) && isMovable )
8550- return CxxValueSemanticsKind::MoveOnly ;
8564+ if (isCopyable )
8565+ continue ;
85518566
8552- if (isCopyable )
8553- return CxxValueSemanticsKind::Copyable ;
8567+ if (isMovable )
8568+ return CxxValueSemanticsKind::MoveOnly ;
85548569
8555- if (isMovable)
8556- return CxxValueSemanticsKind::MoveOnly;
8570+ llvm_unreachable ( " Could not classify C++ type. " );
8571+ }
85578572
8558- llvm_unreachable ( " Could not classify C++ type. " ) ;
8573+ return CxxValueSemanticsKind::Copyable ;
85598574}
85608575
85618576void swift::simple_display (llvm::raw_ostream &out,
0 commit comments