@@ -8215,6 +8215,106 @@ CustomRefCountingOperationResult CustomRefCountingOperation::evaluate(
8215
8215
return {CustomRefCountingOperationResult::tooManyFound, nullptr , name};
8216
8216
}
8217
8217
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
+
8218
8318
void ClangImporter::withSymbolicFeatureEnabled (
8219
8319
llvm::function_ref<void (void )> callback) {
8220
8320
llvm::SaveAndRestore<bool > oldImportSymbolicCXXDecls (
0 commit comments