@@ -8480,103 +8480,118 @@ CxxValueSemanticsKind
84808480CxxValueSemantics::evaluate (Evaluator &evaluator,
84818481 CxxValueSemanticsDescriptor desc) const {
84828482
8483- const auto *type = desc.type ;
8483+ // A C++ type can be imported to Swift as Copyable or ~Copyable.
8484+ // We assume a type can be imported as Copyable unless:
8485+ // - There's no copy constructor
8486+ // - The type has a SWIFT_NONCOPYABLE annotation
8487+ // - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of T is ~Copyable
8488+ // - It is one of the STL types in `STLConditionalParams`
8489+
8490+ const auto *type = desc.type ->getUnqualifiedDesugaredType ();
84848491 auto *importerImpl = desc.importerImpl ;
84858492
8486- auto desugared = type->getUnqualifiedDesugaredType ();
8487- const auto *recordType = desugared->getAs <clang::RecordType>();
8488- if (!recordType)
8489- return CxxValueSemanticsKind::Copyable;
8493+ llvm::SmallVector<clang::RecordDecl *, 4 > stack;
8494+ // Keep track of Decls we've seen to avoid cycles
8495+ llvm::SmallDenseSet<clang::RecordDecl *, 4 > seen;
84908496
8491- auto recordDecl = recordType->getDecl ();
8497+ auto maybePushToStack = [&](const clang::Type *type) {
8498+ auto recordDecl = type->getAsRecordDecl ();
8499+ if (!recordDecl)
8500+ return ;
84928501
8493- // When a reference type is copied, the pointer’s value is copied rather than
8494- // the object’s storage. This means reference types can be imported as
8495- // copyable to Swift, even when they are non-copyable in C++.
8496- if (recordHasReferenceSemantics (recordDecl, importerImpl))
8497- return CxxValueSemanticsKind::Copyable;
8502+ if (seen.insert (recordDecl).second ) {
8503+ // When a reference type is copied, the pointer’s value is copied rather
8504+ // than the object’s storage. This means reference types can be imported
8505+ // as copyable to Swift, even when they are non-copyable in C++.
8506+ if (recordHasReferenceSemantics (recordDecl, importerImpl))
8507+ return ;
84988508
8499- if (recordDecl->isInStdNamespace ()) {
8500- // Hack for a base type of std::optional from the Microsoft standard
8501- // library.
8502- if (recordDecl->getIdentifier () &&
8503- recordDecl->getName () == " _Optional_construct_base" )
8504- return CxxValueSemanticsKind::Copyable;
8505- }
8509+ if (recordDecl->isInStdNamespace ()) {
8510+ // Hack for a base type of std::optional from the Microsoft standard
8511+ // library.
8512+ if (recordDecl->getIdentifier () &&
8513+ recordDecl->getName () == " _Optional_construct_base" )
8514+ return ;
8515+ }
8516+ stack.push_back (recordDecl);
8517+ }
8518+ };
85068519
8507- if (!hasNonCopyableAttr (recordDecl)) {
8508- auto injectedStlAnnotation =
8509- recordDecl->isInStdNamespace ()
8510- ? STLConditionalParams.find (recordDecl->getName ())
8511- : STLConditionalParams.end ();
8512- auto STLParams = injectedStlAnnotation != STLConditionalParams.end ()
8513- ? injectedStlAnnotation->second
8514- : std::vector<int >();
8515- auto conditionalParams = getConditionalCopyableAttrParams (recordDecl);
8520+ maybePushToStack (type);
8521+ while (!stack.empty ()) {
8522+ clang::RecordDecl *recordDecl = stack.back ();
8523+ stack.pop_back ();
85168524
8517- if (!STLParams.empty () || !conditionalParams.empty ()) {
8518- HeaderLoc loc{recordDecl->getLocation ()};
8519- std::function checkArgValueSemantics =
8520- [&](clang::TemplateArgument &arg,
8521- StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8522- if (arg.getKind () != clang::TemplateArgument::Type && importerImpl) {
8523- importerImpl->diagnose (loc, diag::type_template_parameter_expected,
8524- argToCheck);
8525- return CxxValueSemanticsKind::Unknown;
8526- }
8525+ if (!hasNonCopyableAttr (recordDecl)) {
8526+ auto injectedStlAnnotation =
8527+ recordDecl->isInStdNamespace ()
8528+ ? STLConditionalParams.find (recordDecl->getName ())
8529+ : STLConditionalParams.end ();
8530+ auto STLParams = injectedStlAnnotation != STLConditionalParams.end ()
8531+ ? injectedStlAnnotation->second
8532+ : std::vector<int >();
8533+ auto conditionalParams = getConditionalCopyableAttrParams (recordDecl);
8534+
8535+ if (!STLParams.empty () || !conditionalParams.empty ()) {
8536+ HeaderLoc loc{recordDecl->getLocation ()};
8537+ std::function checkArgValueSemantics =
8538+ [&](clang::TemplateArgument &arg,
8539+ StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8540+ if (arg.getKind () != clang::TemplateArgument::Type) {
8541+ if (importerImpl)
8542+ importerImpl->diagnose (
8543+ loc, diag::type_template_parameter_expected, argToCheck);
8544+ return CxxValueSemanticsKind::Unknown;
8545+ }
8546+ maybePushToStack (arg.getAsType ()->getUnqualifiedDesugaredType ());
8547+ // FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request
8548+ return std::nullopt ;
8549+ };
85278550
8528- auto argValueSemantics = evaluateOrDefault (
8529- evaluator,
8530- CxxValueSemantics (
8531- {arg.getAsType ()->getUnqualifiedDesugaredType (), importerImpl}),
8532- {});
8533- if (argValueSemantics != CxxValueSemanticsKind::Copyable)
8534- return argValueSemantics;
8535- return std::nullopt ;
8536- };
8551+ checkConditionalParams<CxxValueSemanticsKind>(
8552+ recordDecl, STLParams, conditionalParams, checkArgValueSemantics);
85378553
8538- auto result = checkConditionalParams<CxxValueSemanticsKind>(
8539- recordDecl, STLParams, conditionalParams, checkArgValueSemantics);
8540- if (result.has_value ())
8541- return result.value ();
8554+ if (importerImpl)
8555+ for (auto name : conditionalParams)
8556+ importerImpl->diagnose (loc, diag::unknown_template_parameter, name);
85428557
8543- if (importerImpl)
8544- for ( auto name : conditionalParams)
8545- importerImpl-> diagnose (loc, diag::unknown_template_parameter, name);
8558+ continue ;
8559+ }
8560+ }
85468561
8547- return CxxValueSemanticsKind::Copyable;
8562+ const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8563+ if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition ()) {
8564+ if (hasNonCopyableAttr (recordDecl))
8565+ return CxxValueSemanticsKind::MoveOnly;
8566+ continue ;
85488567 }
8549- }
85508568
8551- const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8552- if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition ()) {
8553- if (hasNonCopyableAttr (recordDecl))
8554- return CxxValueSemanticsKind::MoveOnly;
8555- return CxxValueSemanticsKind::Copyable;
8556- }
8569+ bool isCopyable = !hasNonCopyableAttr (cxxRecordDecl) &&
8570+ hasCopyTypeOperations (cxxRecordDecl);
8571+ bool isMovable = hasMoveTypeOperations (cxxRecordDecl);
85578572
8558- bool isCopyable = !hasNonCopyableAttr (cxxRecordDecl) &&
8559- hasCopyTypeOperations (cxxRecordDecl);
8560- bool isMovable = hasMoveTypeOperations (cxxRecordDecl);
8573+ if (!hasDestroyTypeOperations (cxxRecordDecl) ||
8574+ (!isCopyable && !isMovable)) {
85618575
8562- if (!hasDestroyTypeOperations (cxxRecordDecl) || (!isCopyable && !isMovable)) {
8576+ if (hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl))
8577+ return CxxValueSemanticsKind::UnavailableConstructors;
85638578
8564- if ( hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl))
8565- return CxxValueSemanticsKind::UnavailableConstructors;
8579+ return CxxValueSemanticsKind::MissingLifetimeOperation;
8580+ }
85668581
8567- return CxxValueSemanticsKind::MissingLifetimeOperation;
8568- }
8582+ if ( hasNonCopyableAttr (cxxRecordDecl) && isMovable)
8583+ return CxxValueSemanticsKind::MoveOnly;
85698584
8570- if ( hasNonCopyableAttr (cxxRecordDecl) && isMovable )
8571- return CxxValueSemanticsKind::MoveOnly ;
8585+ if (isCopyable )
8586+ continue ;
85728587
8573- if (isCopyable )
8574- return CxxValueSemanticsKind::Copyable ;
8588+ if (isMovable )
8589+ return CxxValueSemanticsKind::MoveOnly ;
85758590
8576- if (isMovable)
8577- return CxxValueSemanticsKind::MoveOnly;
8591+ llvm_unreachable ( " Could not classify C++ type. " );
8592+ }
85788593
8579- llvm_unreachable ( " Could not classify C++ type. " ) ;
8594+ return CxxValueSemanticsKind::Copyable ;
85808595}
85818596
85828597void swift::simple_display (llvm::raw_ostream &out,
0 commit comments