9393#include " clang/Serialization/ObjectFilePCHContainerReader.h"
9494#include " clang/Tooling/DependencyScanning/ModuleDepCollector.h"
9595#include " clang/Tooling/DependencyScanning/ScanAndUpdateArgs.h"
96+ #include " llvm/ADT/DenseSet.h"
9697#include " llvm/ADT/IntrusiveRefCntPtr.h"
9798#include " llvm/ADT/STLExtras.h"
9899#include " llvm/ADT/SmallVector.h"
@@ -8704,7 +8705,7 @@ SourceLoc swift::extractNearestSourceLoc(SafeUseOfCxxDeclDescriptor desc) {
87048705}
87058706
87068707void swift::simple_display (llvm::raw_ostream &out,
8707- CxxDeclExplicitSafetyDescriptor desc) {
8708+ ClangDeclExplicitSafetyDescriptor desc) {
87088709 out << " Checking if '" ;
87098710 if (auto namedDecl = dyn_cast<clang::NamedDecl>(desc.decl ))
87108711 out << namedDecl->getNameAsString ();
@@ -8713,7 +8714,7 @@ void swift::simple_display(llvm::raw_ostream &out,
87138714 out << " ' is explicitly safe.\n " ;
87148715}
87158716
8716- SourceLoc swift::extractNearestSourceLoc (CxxDeclExplicitSafetyDescriptor desc) {
8717+ SourceLoc swift::extractNearestSourceLoc (ClangDeclExplicitSafetyDescriptor desc) {
87178718 return SourceLoc ();
87188719}
87198720
@@ -8772,103 +8773,132 @@ CustomRefCountingOperationResult CustomRefCountingOperation::evaluate(
87728773 return {CustomRefCountingOperationResult::tooManyFound, nullptr , name};
87738774}
87748775
8775- // / Check whether the given Clang type involves an unsafe type.
8776- static bool hasUnsafeType (Evaluator &evaluator, clang::QualType clangType) {
8777- // Handle pointers.
8778- auto pointeeType = clangType->getPointeeType ();
8779- if (!pointeeType.isNull ()) {
8780- // Function pointers are okay.
8781- if (pointeeType->isFunctionType ())
8782- return false ;
8783-
8784- // Pointers to record types are okay if they come in as foreign reference
8785- // types.
8786- if (auto recordDecl = pointeeType->getAsRecordDecl ()) {
8787- if (hasImportAsRefAttr (recordDecl))
8788- return false ;
8776+ ExplicitSafety ClangDeclExplicitSafety::evaluate (
8777+ Evaluator &evaluator, ClangDeclExplicitSafetyDescriptor desc) const {
8778+ // FIXME: Also similar to hasPointerInSubobjects
8779+ // FIXME: should probably also subsume IsSafeUseOfCxxDecl
8780+
8781+ if (desc.isClass )
8782+ // Safety for class types is handled a bit differently than other types.
8783+ // If it is not explicitly marked unsafe, it is always explicitly safe.
8784+ return hasSwiftAttribute (desc.decl , " unsafe" ) ? ExplicitSafety::Unsafe
8785+ : ExplicitSafety::Safe;
8786+
8787+ // Clang record types are considered explicitly unsafe if any of their fields,
8788+ // base classes, and template type parameters are unsafe. We use a stack for
8789+ // this recursive traversal.
8790+ //
8791+ // Invariant: if any Decl in the stack is unsafe, then desc.decl is unsafe.
8792+ llvm::SmallVector<const clang::Decl *, 4 > stack;
8793+
8794+ // Keep track of which Decls we've seen to avoid cycles.
8795+ llvm::SmallDenseSet<const clang::Decl *, 4 > seen;
8796+
8797+ // Check whether a type is unsafe. This function may also push to the stack.
8798+ auto isUnsafe = [&](clang::QualType type) -> bool {
8799+ auto pointeeType = type->getPointeeType ();
8800+ if (!pointeeType.isNull ()) {
8801+ if (pointeeType->isFunctionType ())
8802+ return false ; // Function pointers are not unsafe
8803+ auto *recordDecl = pointeeType->getAsRecordDecl ();
8804+ if (recordDecl && hasImportAsRefAttr (recordDecl))
8805+ return false ; // Pointers are ok if imported as foreign reference types
8806+ return true ; // All other pointers are considered unsafe.
8807+ }
8808+ if (auto *decl = type->getAsTagDecl ()) {
8809+ // We need to check the safety of the TagDecl corresponding to this type
8810+ if (seen.insert (decl).second )
8811+ // Only visit decl if we have not seen it before, to avoid cycles
8812+ stack.push_back (decl);
8813+ }
8814+ return false ; // This type does not look unsafe on its own
8815+ };
8816+
8817+ stack.push_back (desc.decl );
8818+ seen.insert (desc.decl );
8819+ while (!stack.empty ()) {
8820+ const clang::Decl *decl = stack.back ();
8821+ stack.pop_back ();
8822+
8823+ // Found unsafe; whether decl == desc.decl or not, desc.decl is unsafe
8824+ // (see invariant, above)
8825+ if (hasSwiftAttribute (decl, " unsafe" ))
8826+ return ExplicitSafety::Unsafe;
8827+
8828+ if (hasSwiftAttribute (decl, " safe" ))
8829+ continue ;
8830+
8831+ // Enums are always safe
8832+ if (isa<clang::EnumDecl>(decl))
8833+ continue ;
8834+
8835+ auto *recordDecl = dyn_cast<clang::RecordDecl>(decl);
8836+ if (!recordDecl) {
8837+ if (decl == desc.decl )
8838+ // If desc.decl is not a RecordDecl or EnumDecl, safety is unspecified.
8839+ return ExplicitSafety::Unspecified;
8840+ // If we encountered non-Record non-Enum decl during recursive traversal,
8841+ // we need to continue checking safety of other decls.
8842+ continue ;
87898843 }
8790-
8791- // All other pointers are considered unsafe.
8792- return true ;
8793- }
87948844
8795- // Handle records recursively.
8796- if (auto recordDecl = clangType->getAsTagDecl ()) {
8797- // If we reached this point the types is not imported as a shared reference,
8798- // so we don't need to check the bases whether they are shared references.
8799- auto safety = evaluateOrDefault (
8800- evaluator, ClangDeclExplicitSafety ({recordDecl, false }),
8801- ExplicitSafety::Unspecified);
8802- switch (safety) {
8803- case ExplicitSafety::Unsafe:
8804- return true ;
8805-
8806- case ExplicitSafety::Safe:
8807- case ExplicitSafety::Unspecified:
8808- return false ;
8845+ // Escapability annotations imply that the declaration is safe
8846+ if (evaluateOrDefault (
8847+ evaluator,
8848+ ClangTypeEscapability ({recordDecl->getTypeForDecl (), nullptr }),
8849+ CxxEscapability::Unknown) != CxxEscapability::Unknown)
8850+ continue ;
8851+
8852+ // A template class is unsafe if any of its type arguments are unsafe.
8853+ // Note that this does not rely on the record being defined.
8854+ if (auto *specDecl =
8855+ dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
8856+ for (auto arg : specDecl->getTemplateArgs ().asArray ()) {
8857+ switch (arg.getKind ()) {
8858+ case clang::TemplateArgument::Type:
8859+ if (isUnsafe (arg.getAsType ()))
8860+ return ExplicitSafety::Unsafe;
8861+ break ;
8862+ case clang::TemplateArgument::Pack:
8863+ for (auto pkArg : arg.getPackAsArray ()) {
8864+ if (pkArg.getKind () == clang::TemplateArgument::Type &&
8865+ isUnsafe (pkArg.getAsType ()))
8866+ return ExplicitSafety::Unsafe;
8867+ }
8868+ break ;
8869+ default :
8870+ continue ;
8871+ }
8872+ }
88098873 }
8810- }
8811-
8812- // Everything else is safe.
8813- return false ;
8814- }
88158874
8816- ExplicitSafety
8817- ClangDeclExplicitSafety::evaluate (Evaluator &evaluator,
8818- CxxDeclExplicitSafetyDescriptor desc) const {
8819- // FIXME: Also similar to hasPointerInSubobjects
8820- // FIXME: should probably also subsume IsSafeUseOfCxxDecl
8821-
8822- // Explicitly unsafe.
8823- auto decl = desc.decl ;
8824- if (hasSwiftAttribute (decl, " unsafe" ))
8825- return ExplicitSafety::Unsafe;
8826-
8827- // Explicitly safe.
8828- if (hasSwiftAttribute (decl, " safe" ))
8829- return ExplicitSafety::Safe;
8830-
8831- // Shared references are considered safe.
8832- if (desc.isClass )
8833- return ExplicitSafety::Safe;
8834-
8835- // Enums are always safe.
8836- if (isa<clang::EnumDecl>(decl))
8837- return ExplicitSafety::Safe;
8838-
8839- // If it's not a record, leave it unspecified.
8840- auto recordDecl = dyn_cast<clang::RecordDecl>(decl);
8841- if (!recordDecl)
8842- return ExplicitSafety::Unspecified;
8843-
8844- // Escapable and non-escapable annotations imply that the declaration is
8845- // safe.
8846- if (evaluateOrDefault (
8847- evaluator,
8848- ClangTypeEscapability ({recordDecl->getTypeForDecl (), nullptr }),
8849- CxxEscapability::Unknown) != CxxEscapability::Unknown)
8850- return ExplicitSafety::Safe;
8851-
8852- // If we don't have a definition, leave it unspecified.
8853- recordDecl = recordDecl->getDefinition ();
8854- if (!recordDecl)
8855- return ExplicitSafety::Unspecified;
8856-
8857- // If this is a C++ class, check its bases.
8858- if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl)) {
8859- for (auto base : cxxRecordDecl->bases ()) {
8860- if (hasUnsafeType (evaluator, base.getType ()))
8875+ recordDecl = recordDecl->getDefinition ();
8876+ if (!recordDecl) {
8877+ if (decl == desc.decl )
8878+ // If desc.decl doesn't have a definition, safety is unspecified.
8879+ return ExplicitSafety::Unspecified;
8880+ // If we encountered decl without definition during recursive traversal,
8881+ // we need to continue checking safety of other decls.
8882+ continue ;
8883+ }
8884+
8885+ if (auto *cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl)) {
8886+ for (auto base : cxxRecordDecl->bases ()) {
8887+ if (isUnsafe (base.getType ()))
8888+ return ExplicitSafety::Unsafe;
8889+ }
8890+ }
8891+
8892+ for (auto *field : recordDecl->fields ()) {
8893+ if (isUnsafe (field->getType ()))
88618894 return ExplicitSafety::Unsafe;
88628895 }
88638896 }
8864-
8865- // Check the fields.
8866- for (auto field : recordDecl->fields ()) {
8867- if (hasUnsafeType (evaluator, field->getType ()))
8868- return ExplicitSafety::Unsafe;
8869- }
88708897
8871- // Okay, call it safe.
8898+ // desc.decl isn't explicitly marked unsafe, and none of the types/decls
8899+ // reachable from desc.decl are considered unsafe either. Cases where we would
8900+ // consider desc.decl's safety unspecified should have returned early from the
8901+ // loop. Thus, we can conclude that desc.decl is safe.
88728902 return ExplicitSafety::Safe;
88738903}
88748904
0 commit comments