diff --git a/include/swift/ClangImporter/ClangImporterRequests.h b/include/swift/ClangImporter/ClangImporterRequests.h index e05db6edf2378..8a3a88acae1d3 100644 --- a/include/swift/ClangImporter/ClangImporterRequests.h +++ b/include/swift/ClangImporter/ClangImporterRequests.h @@ -576,10 +576,37 @@ class ClangTypeEscapability void simple_display(llvm::raw_ostream &out, EscapabilityLookupDescriptor desc); SourceLoc extractNearestSourceLoc(EscapabilityLookupDescriptor desc); +struct CxxDeclExplicitSafetyDescriptor final { + const clang::Decl *decl; + bool isClass; + + CxxDeclExplicitSafetyDescriptor(const clang::Decl *decl, bool isClass) + : decl(decl), isClass(isClass) {} + + friend llvm::hash_code + hash_value(const CxxDeclExplicitSafetyDescriptor &desc) { + return llvm::hash_combine(desc.decl, desc.isClass); + } + + friend bool operator==(const CxxDeclExplicitSafetyDescriptor &lhs, + const CxxDeclExplicitSafetyDescriptor &rhs) { + return lhs.decl == rhs.decl && lhs.isClass == rhs.isClass; + } + + friend bool operator!=(const CxxDeclExplicitSafetyDescriptor &lhs, + const CxxDeclExplicitSafetyDescriptor &rhs) { + return !(lhs == rhs); + } +}; + +void simple_display(llvm::raw_ostream &out, + CxxDeclExplicitSafetyDescriptor desc); +SourceLoc extractNearestSourceLoc(CxxDeclExplicitSafetyDescriptor desc); + /// Determine the safety of the given Clang declaration. class ClangDeclExplicitSafety : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -592,7 +619,8 @@ class ClangDeclExplicitSafety friend SimpleRequest; // Evaluation. - ExplicitSafety evaluate(Evaluator &evaluator, SafeUseOfCxxDeclDescriptor desc) const; + ExplicitSafety evaluate(Evaluator &evaluator, + CxxDeclExplicitSafetyDescriptor desc) const; }; #define SWIFT_TYPEID_ZONE ClangImporter diff --git a/include/swift/ClangImporter/ClangImporterTypeIDZone.def b/include/swift/ClangImporter/ClangImporterTypeIDZone.def index b4ea68a4053a2..2d81f93181ac3 100644 --- a/include/swift/ClangImporter/ClangImporterTypeIDZone.def +++ b/include/swift/ClangImporter/ClangImporterTypeIDZone.def @@ -46,5 +46,5 @@ SWIFT_REQUEST(ClangImporter, ClangTypeEscapability, CxxEscapability(EscapabilityLookupDescriptor), Cached, NoLocationInfo) SWIFT_REQUEST(ClangImporter, ClangDeclExplicitSafety, - ExplicitSafety(SafeUseOfCxxDeclDescriptor), Cached, + ExplicitSafety(CxxDeclExplicitSafetyDescriptor), Cached, NoLocationInfo) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 345a155cc805f..418dce9439db3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1244,9 +1244,10 @@ ExplicitSafety Decl::getExplicitSafety() const { // If this declaration is from C, ask the Clang importer. if (auto clangDecl = getClangDecl()) { ASTContext &ctx = getASTContext(); - return evaluateOrDefault(ctx.evaluator, - ClangDeclExplicitSafety({clangDecl}), - ExplicitSafety::Unspecified); + return evaluateOrDefault( + ctx.evaluator, + ClangDeclExplicitSafety({clangDecl, isa(this)}), + ExplicitSafety::Unspecified); } // Inference: Check the enclosing context, unless this is a type. diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 9db9c4ca8b89d..31124de311a97 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -24,6 +24,7 @@ #include "swift/AST/Builtins.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/ConcreteDeclRef.h" +#include "swift/AST/Decl.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsClangImporter.h" #include "swift/AST/DiagnosticsSema.h" @@ -8391,6 +8392,20 @@ SourceLoc swift::extractNearestSourceLoc(SafeUseOfCxxDeclDescriptor desc) { return SourceLoc(); } +void swift::simple_display(llvm::raw_ostream &out, + CxxDeclExplicitSafetyDescriptor desc) { + out << "Checking if '"; + if (auto namedDecl = dyn_cast(desc.decl)) + out << namedDecl->getNameAsString(); + else + out << ""; + out << "' is explicitly safe.\n"; +} + +SourceLoc swift::extractNearestSourceLoc(CxxDeclExplicitSafetyDescriptor desc) { + return SourceLoc(); +} + CustomRefCountingOperationResult CustomRefCountingOperation::evaluate( Evaluator &evaluator, CustomRefCountingOperationDescriptor desc) const { auto swiftDecl = desc.decl; @@ -8468,9 +8483,11 @@ static bool hasUnsafeType(Evaluator &evaluator, clang::QualType clangType) { // Handle records recursively. if (auto recordDecl = clangType->getAsTagDecl()) { - auto safety = - evaluateOrDefault(evaluator, ClangDeclExplicitSafety({recordDecl}), - ExplicitSafety::Unspecified); + // If we reached this point the types is not imported as a shared reference, + // so we don't need to check the bases whether they are shared references. + auto safety = evaluateOrDefault( + evaluator, ClangDeclExplicitSafety({recordDecl, false}), + ExplicitSafety::Unspecified); switch (safety) { case ExplicitSafety::Unsafe: return true; @@ -8485,10 +8502,9 @@ static bool hasUnsafeType(Evaluator &evaluator, clang::QualType clangType) { return false; } -ExplicitSafety ClangDeclExplicitSafety::evaluate( - Evaluator &evaluator, - SafeUseOfCxxDeclDescriptor desc -) const { +ExplicitSafety +ClangDeclExplicitSafety::evaluate(Evaluator &evaluator, + CxxDeclExplicitSafetyDescriptor desc) const { // FIXME: Somewhat duplicative with importAsUnsafe. // FIXME: Also similar to hasPointerInSubobjects // FIXME: should probably also subsume IsSafeUseOfCxxDecl @@ -8501,7 +8517,11 @@ ExplicitSafety ClangDeclExplicitSafety::evaluate( // Explicitly safe. if (hasSwiftAttribute(decl, "safe")) return ExplicitSafety::Safe; - + + // Shared references are considered safe. + if (desc.isClass) + return ExplicitSafety::Safe; + // Enums are always safe. if (isa(decl)) return ExplicitSafety::Safe; diff --git a/test/Interop/Cxx/class/safe-interop-mode.swift b/test/Interop/Cxx/class/safe-interop-mode.swift index fab3578028017..45b6a2b4a621d 100644 --- a/test/Interop/Cxx/class/safe-interop-mode.swift +++ b/test/Interop/Cxx/class/safe-interop-mode.swift @@ -63,6 +63,16 @@ View safeFunc(View v1 [[clang::noescape]], View v2 [[clang::lifetimebound]]); // Second non-escapable type is not annotated in any way. void unsafeFunc(View v1 [[clang::noescape]], View v2); +class SharedObject { +private: + int *p; +} SWIFT_SHARED_REFERENCE(retainSharedObject, releaseSharedObject); + +inline void retainSharedObject(SharedObject *) {} +inline void releaseSharedObject(SharedObject *) {} + +struct DerivedFromSharedObject : SharedObject {}; + //--- test.swift import Test @@ -134,3 +144,13 @@ func useUnsafeLifetimeAnnotated(v: View) { // expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}} unsafeFunc(v, v) // expected-note{{reference to unsafe global function 'unsafeFunc'}} } + +@available(SwiftStdlib 5.8, *) +func useSharedReference(frt: SharedObject) { + let _ = frt +} + +@available(SwiftStdlib 5.8, *) +func useSharedReference(frt: DerivedFromSharedObject) { + let _ = frt +}