@@ -8215,6 +8215,106 @@ CustomRefCountingOperationResult CustomRefCountingOperation::evaluate(
82158215 return {CustomRefCountingOperationResult::tooManyFound, nullptr , name};
82168216}
82178217
8218+ // / Check whether the given Clang type involves an unsafe type.
8219+ static bool hasUnsafeType (
8220+ Evaluator &evaluator, ASTContext &swiftContext, clang::QualType clangType
8221+ ) {
8222+ // Handle pointers.
8223+ auto pointeeType = clangType->getPointeeType ();
8224+ if (!pointeeType.isNull ()) {
8225+ // Function pointers are okay.
8226+ if (pointeeType->isFunctionType ())
8227+ return false ;
8228+
8229+ // Pointers to record types are okay if they come in as foreign reference
8230+ // types.
8231+ if (auto recordDecl = pointeeType->getAsRecordDecl ()) {
8232+ if (hasImportAsRefAttr (recordDecl))
8233+ return false ;
8234+ }
8235+
8236+ // All other pointers are considered unsafe.
8237+ return true ;
8238+ }
8239+
8240+ // Handle records recursively.
8241+ if (auto recordDecl = clangType->getAsTagDecl ()) {
8242+ auto safety = evaluateOrDefault (
8243+ evaluator,
8244+ ClangDeclExplicitSafety ({recordDecl, swiftContext}),
8245+ ExplicitSafety::Unspecified);
8246+ switch (safety) {
8247+ case ExplicitSafety::Unsafe:
8248+ return true ;
8249+
8250+ case ExplicitSafety::Safe:
8251+ case ExplicitSafety::Unspecified:
8252+ return false ;
8253+ }
8254+ }
8255+
8256+ // Everything else is safe.
8257+ return false ;
8258+ }
8259+
8260+ ExplicitSafety ClangDeclExplicitSafety::evaluate (
8261+ Evaluator &evaluator,
8262+ SafeUseOfCxxDeclDescriptor desc
8263+ ) const {
8264+ // FIXME: Somewhat duplicative with importAsUnsafe.
8265+ // FIXME: Also similar to hasPointerInSubobjects
8266+ // FIXME: should probably also subsume IsSafeUseOfCxxDecl
8267+
8268+ // Explicitly unsafe.
8269+ auto decl = desc.decl ;
8270+ if (hasUnsafeAPIAttr (decl) || hasSwiftAttribute (decl, " unsafe" ))
8271+ return ExplicitSafety::Unsafe;
8272+
8273+ // Explicitly safe.
8274+ if (hasSwiftAttribute (decl, " safe" ))
8275+ return ExplicitSafety::Safe;
8276+
8277+ // Enums are always safe.
8278+ if (isa<clang::EnumDecl>(decl))
8279+ return ExplicitSafety::Safe;
8280+
8281+ // If it's not a record, leave it unspecified.
8282+ auto recordDecl = dyn_cast<clang::RecordDecl>(decl);
8283+ if (!recordDecl)
8284+ return ExplicitSafety::Unspecified;
8285+
8286+ // Escapable and non-escapable annotations imply that the declaration is
8287+ // safe.
8288+ if (hasNonEscapableAttr (recordDecl) || hasEscapableAttr (recordDecl))
8289+ return ExplicitSafety::Safe;
8290+
8291+ // If we don't have a definition, leave it unspecified.
8292+ recordDecl = recordDecl->getDefinition ();
8293+ if (!recordDecl)
8294+ return ExplicitSafety::Unspecified;
8295+
8296+ // If this is a C++ class, check its bases.
8297+ if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl)) {
8298+ for (auto base : cxxRecordDecl->bases ()) {
8299+ if (hasUnsafeType (evaluator, desc.ctx , base.getType ()))
8300+ return ExplicitSafety::Unsafe;
8301+ }
8302+ }
8303+
8304+ // Check the fields.
8305+ for (auto field : recordDecl->fields ()) {
8306+ if (hasUnsafeType (evaluator, desc.ctx , field->getType ()))
8307+ return ExplicitSafety::Unsafe;
8308+ }
8309+
8310+ // Okay, call it safe.
8311+ return ExplicitSafety::Safe;
8312+ }
8313+
8314+ bool ClangDeclExplicitSafety::isCached () const {
8315+ return isa<clang::RecordDecl>(std::get<0 >(getStorage ()).decl );
8316+ }
8317+
82188318void ClangImporter::withSymbolicFeatureEnabled (
82198319 llvm::function_ref<void (void )> callback) {
82208320 llvm::SaveAndRestore<bool > oldImportSymbolicCXXDecls (
0 commit comments