@@ -6312,6 +6312,19 @@ static bool hasImportAsRefAttr(const clang::RecordDecl *decl) {
63126312 });
63136313}
63146314
6315+ // Is this a pointer to a foreign reference type.
6316+ static bool isForeignReferenceType (const clang::QualType type) {
6317+ if (!type->isPointerType ())
6318+ return false ;
6319+
6320+ auto pointeeType =
6321+ dyn_cast<clang::RecordType>(type->getPointeeType ().getCanonicalType ());
6322+ if (pointeeType == nullptr )
6323+ return false ;
6324+
6325+ return hasImportAsRefAttr (pointeeType->getDecl ());
6326+ }
6327+
63156328static bool hasOwnedValueAttr (const clang::RecordDecl *decl) {
63166329 // Hard-coded special cases from the standard library (this will go away once
63176330 // API notes support namespaces).
@@ -6474,14 +6487,16 @@ CxxRecordSemanticsKind
64746487CxxRecordSemantics::evaluate (Evaluator &evaluator,
64756488 CxxRecordSemanticsDescriptor desc) const {
64766489 const auto *decl = desc.decl ;
6490+ auto &clangSema = desc.ctx .getClangModuleLoader ()->getClangSema ();
64776491
64786492 if (hasImportAsRefAttr (decl)) {
64796493 return CxxRecordSemanticsKind::Reference;
64806494 }
64816495
64826496 auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl);
6483- if (!cxxDecl)
6497+ if (!cxxDecl) {
64846498 return CxxRecordSemanticsKind::Trivial;
6499+ }
64856500
64866501 if (!hasRequiredValueTypeOperations (cxxDecl)) {
64876502 if (hasUnsafeAPIAttr (cxxDecl))
@@ -6523,58 +6538,52 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
65236538bool IsSafeUseOfCxxDecl::evaluate (Evaluator &evaluator,
65246539 SafeUseOfCxxDeclDescriptor desc) const {
65256540 const clang::Decl *decl = desc.decl ;
6526- const clang::CXXRecordDecl *recordDecl = nullptr ;
6527- bool cxxMethodIsSafe = true ;
65286541
65296542 if (auto method = dyn_cast<clang::CXXMethodDecl>(decl)) {
6543+ // The user explicitly asked us to import this method.
65306544 if (hasUnsafeAPIAttr (method))
65316545 return true ;
65326546
6547+ // If it's a static method, it cannot project anything. It's fine.
65336548 if (method->isOverloadedOperator () || method->isStatic () ||
65346549 isa<clang::CXXConstructorDecl>(decl))
65356550 return true ;
65366551
6552+ if (isForeignReferenceType (method->getReturnType ()))
6553+ return true ;
6554+
6555+ // If it returns a pointer or reference, that's a projection.
65376556 if (method->getReturnType ()->isPointerType () ||
65386557 method->getReturnType ()->isReferenceType ())
6539- cxxMethodIsSafe = false ;
6558+ return false ;
65406559
6560+ // Try to figure out the semantics of the return type. If it's a
6561+ // pointer/iterator, it's unsafe.
65416562 if (auto returnType = dyn_cast<clang::RecordType>(
65426563 method->getReturnType ().getCanonicalType ())) {
65436564 if (auto cxxRecordReturnType =
65446565 dyn_cast<clang::CXXRecordDecl>(returnType->getDecl ())) {
6545- auto semanticsKind = evaluateOrDefault (
6546- evaluator, CxxRecordSemantics ({cxxRecordReturnType, desc.ctx }), {});
6547-
6548- if (semanticsKind == CxxRecordSemanticsKind::UnsafePointerMember ||
6549- // Pretend all methods that return iterators are unsafe so protocol
6550- // conformances work.
6551- semanticsKind == CxxRecordSemanticsKind::Iterator)
6552- cxxMethodIsSafe = false ;
6566+ if (hasIteratorAPIAttr (cxxRecordReturnType) ||
6567+ isIterator (cxxRecordReturnType)) {
6568+ return false ;
6569+ }
6570+
6571+ // Mark this as safe to help our diganostics down the road.
6572+ if (!cxxRecordReturnType->getDefinition ()) {
6573+ return true ;
6574+ }
6575+
6576+ if (!cxxRecordReturnType->hasUserDeclaredCopyConstructor () &&
6577+ !cxxRecordReturnType->hasUserDeclaredMoveConstructor () &&
6578+ hasPointerInSubobjects (cxxRecordReturnType)) {
6579+ return false ;
6580+ }
65536581 }
65546582 }
6555-
6556- recordDecl = method->getParent ();
6557- } else if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(decl)) {
6558- recordDecl = cxxRecordDecl;
6559- } else {
6560- llvm_unreachable (" decl must be a C++ method or C++ record." );
65616583 }
65626584
6563- auto semanticsKind = evaluateOrDefault (
6564- evaluator, CxxRecordSemantics ({recordDecl, desc.ctx }), {});
6565-
6566- // Always unsafe.
6567- if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation)
6568- return false ;
6569-
6570- // Always OK.
6571- if (semanticsKind == CxxRecordSemanticsKind::Reference)
6572- return true ;
6573-
6574-
6575- // All other record semantics kinds are some varient of an "owned" type, so
6576- // dis-allow potential projections.
6577- return cxxMethodIsSafe;
6585+ // Otherwise, it's safe.
6586+ return true ;
65786587}
65796588
65806589void swift::simple_display (llvm::raw_ostream &out,
0 commit comments