@@ -6235,6 +6235,19 @@ static bool hasImportAsRefAttr(const clang::RecordDecl *decl) {
62356235 });
62366236}
62376237
6238+ // Is this a pointer to a foreign reference type.
6239+ static bool isForeignReferenceType (const clang::QualType type) {
6240+ if (!type->isPointerType ())
6241+ return false ;
6242+
6243+ auto pointeeType =
6244+ dyn_cast<clang::RecordType>(type->getPointeeType ().getCanonicalType ());
6245+ if (pointeeType == nullptr )
6246+ return false ;
6247+
6248+ return hasImportAsRefAttr (pointeeType->getDecl ());
6249+ }
6250+
62386251static bool hasOwnedValueAttr (const clang::RecordDecl *decl) {
62396252 // Hard-coded special cases from the standard library (this will go away once
62406253 // API notes support namespaces).
@@ -6397,14 +6410,16 @@ CxxRecordSemanticsKind
63976410CxxRecordSemantics::evaluate (Evaluator &evaluator,
63986411 CxxRecordSemanticsDescriptor desc) const {
63996412 const auto *decl = desc.decl ;
6413+ auto &clangSema = desc.ctx .getClangModuleLoader ()->getClangSema ();
64006414
64016415 if (hasImportAsRefAttr (decl)) {
64026416 return CxxRecordSemanticsKind::Reference;
64036417 }
64046418
64056419 auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl);
6406- if (!cxxDecl)
6420+ if (!cxxDecl) {
64076421 return CxxRecordSemanticsKind::Trivial;
6422+ }
64086423
64096424 if (!hasRequiredValueTypeOperations (cxxDecl)) {
64106425 if (hasUnsafeAPIAttr (cxxDecl))
@@ -6446,58 +6461,52 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
64466461bool IsSafeUseOfCxxDecl::evaluate (Evaluator &evaluator,
64476462 SafeUseOfCxxDeclDescriptor desc) const {
64486463 const clang::Decl *decl = desc.decl ;
6449- const clang::CXXRecordDecl *recordDecl = nullptr ;
6450- bool cxxMethodIsSafe = true ;
64516464
64526465 if (auto method = dyn_cast<clang::CXXMethodDecl>(decl)) {
6466+ // The user explicitly asked us to import this method.
64536467 if (hasUnsafeAPIAttr (method))
64546468 return true ;
64556469
6470+ // If it's a static method, it cannot project anything. It's fine.
64566471 if (method->isOverloadedOperator () || method->isStatic () ||
64576472 isa<clang::CXXConstructorDecl>(decl))
64586473 return true ;
64596474
6475+ if (isForeignReferenceType (method->getReturnType ()))
6476+ return true ;
6477+
6478+ // If it returns a pointer or reference, that's a projection.
64606479 if (method->getReturnType ()->isPointerType () ||
64616480 method->getReturnType ()->isReferenceType ())
6462- cxxMethodIsSafe = false ;
6481+ return false ;
64636482
6483+ // Try to figure out the semantics of the return type. If it's a
6484+ // pointer/iterator, it's unsafe.
64646485 if (auto returnType = dyn_cast<clang::RecordType>(
64656486 method->getReturnType ().getCanonicalType ())) {
64666487 if (auto cxxRecordReturnType =
64676488 dyn_cast<clang::CXXRecordDecl>(returnType->getDecl ())) {
6468- auto semanticsKind = evaluateOrDefault (
6469- evaluator, CxxRecordSemantics ({cxxRecordReturnType, desc.ctx }), {});
6470-
6471- if (semanticsKind == CxxRecordSemanticsKind::UnsafePointerMember ||
6472- // Pretend all methods that return iterators are unsafe so protocol
6473- // conformances work.
6474- semanticsKind == CxxRecordSemanticsKind::Iterator)
6475- cxxMethodIsSafe = false ;
6489+ if (hasIteratorAPIAttr (cxxRecordReturnType) ||
6490+ isIterator (cxxRecordReturnType)) {
6491+ return false ;
6492+ }
6493+
6494+ // Mark this as safe to help our diganostics down the road.
6495+ if (!cxxRecordReturnType->getDefinition ()) {
6496+ return true ;
6497+ }
6498+
6499+ if (!cxxRecordReturnType->hasUserDeclaredCopyConstructor () &&
6500+ !cxxRecordReturnType->hasUserDeclaredMoveConstructor () &&
6501+ hasPointerInSubobjects (cxxRecordReturnType)) {
6502+ return false ;
6503+ }
64766504 }
64776505 }
6478-
6479- recordDecl = method->getParent ();
6480- } else if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(decl)) {
6481- recordDecl = cxxRecordDecl;
6482- } else {
6483- llvm_unreachable (" decl must be a C++ method or C++ record." );
64846506 }
64856507
6486- auto semanticsKind = evaluateOrDefault (
6487- evaluator, CxxRecordSemantics ({recordDecl, desc.ctx }), {});
6488-
6489- // Always unsafe.
6490- if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation)
6491- return false ;
6492-
6493- // Always OK.
6494- if (semanticsKind == CxxRecordSemanticsKind::Reference)
6495- return true ;
6496-
6497-
6498- // All other record semantics kinds are some varient of an "owned" type, so
6499- // dis-allow potential projections.
6500- return cxxMethodIsSafe;
6508+ // Otherwise, it's safe.
6509+ return true ;
65016510}
65026511
65036512void swift::simple_display (llvm::raw_ostream &out,
0 commit comments