@@ -6235,6 +6235,19 @@ static bool hasImportAsRefAttr(const clang::RecordDecl *decl) {
6235
6235
});
6236
6236
}
6237
6237
6238
+ // Is this a pointer to a foreign reference type.
6239
+ static bool isForeignReferenceType (const clang::QualType type) {
6240
+ if (!type->isPointerType ())
6241
+ return false ;
6242
+
6243
+ auto pointeeType =
6244
+ dyn_cast<clang::RecordType>(type->getPointeeType ().getCanonicalType ());
6245
+ if (pointeeType == nullptr )
6246
+ return false ;
6247
+
6248
+ return hasImportAsRefAttr (pointeeType->getDecl ());
6249
+ }
6250
+
6238
6251
static bool hasOwnedValueAttr (const clang::RecordDecl *decl) {
6239
6252
// Hard-coded special cases from the standard library (this will go away once
6240
6253
// API notes support namespaces).
@@ -6397,14 +6410,16 @@ CxxRecordSemanticsKind
6397
6410
CxxRecordSemantics::evaluate (Evaluator &evaluator,
6398
6411
CxxRecordSemanticsDescriptor desc) const {
6399
6412
const auto *decl = desc.decl ;
6413
+ auto &clangSema = desc.ctx .getClangModuleLoader ()->getClangSema ();
6400
6414
6401
6415
if (hasImportAsRefAttr (decl)) {
6402
6416
return CxxRecordSemanticsKind::Reference;
6403
6417
}
6404
6418
6405
6419
auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl);
6406
- if (!cxxDecl)
6420
+ if (!cxxDecl) {
6407
6421
return CxxRecordSemanticsKind::Trivial;
6422
+ }
6408
6423
6409
6424
if (!hasRequiredValueTypeOperations (cxxDecl)) {
6410
6425
if (hasUnsafeAPIAttr (cxxDecl))
@@ -6446,58 +6461,52 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
6446
6461
bool IsSafeUseOfCxxDecl::evaluate (Evaluator &evaluator,
6447
6462
SafeUseOfCxxDeclDescriptor desc) const {
6448
6463
const clang::Decl *decl = desc.decl ;
6449
- const clang::CXXRecordDecl *recordDecl = nullptr ;
6450
- bool cxxMethodIsSafe = true ;
6451
6464
6452
6465
if (auto method = dyn_cast<clang::CXXMethodDecl>(decl)) {
6466
+ // The user explicitly asked us to import this method.
6453
6467
if (hasUnsafeAPIAttr (method))
6454
6468
return true ;
6455
6469
6470
+ // If it's a static method, it cannot project anything. It's fine.
6456
6471
if (method->isOverloadedOperator () || method->isStatic () ||
6457
6472
isa<clang::CXXConstructorDecl>(decl))
6458
6473
return true ;
6459
6474
6475
+ if (isForeignReferenceType (method->getReturnType ()))
6476
+ return true ;
6477
+
6478
+ // If it returns a pointer or reference, that's a projection.
6460
6479
if (method->getReturnType ()->isPointerType () ||
6461
6480
method->getReturnType ()->isReferenceType ())
6462
- cxxMethodIsSafe = false ;
6481
+ return false ;
6463
6482
6483
+ // Try to figure out the semantics of the return type. If it's a
6484
+ // pointer/iterator, it's unsafe.
6464
6485
if (auto returnType = dyn_cast<clang::RecordType>(
6465
6486
method->getReturnType ().getCanonicalType ())) {
6466
6487
if (auto cxxRecordReturnType =
6467
6488
dyn_cast<clang::CXXRecordDecl>(returnType->getDecl ())) {
6468
- auto semanticsKind = evaluateOrDefault (
6469
- evaluator, CxxRecordSemantics ({cxxRecordReturnType, desc.ctx }), {});
6470
-
6471
- if (semanticsKind == CxxRecordSemanticsKind::UnsafePointerMember ||
6472
- // Pretend all methods that return iterators are unsafe so protocol
6473
- // conformances work.
6474
- semanticsKind == CxxRecordSemanticsKind::Iterator)
6475
- cxxMethodIsSafe = false ;
6489
+ if (hasIteratorAPIAttr (cxxRecordReturnType) ||
6490
+ isIterator (cxxRecordReturnType)) {
6491
+ return false ;
6492
+ }
6493
+
6494
+ // Mark this as safe to help our diganostics down the road.
6495
+ if (!cxxRecordReturnType->getDefinition ()) {
6496
+ return true ;
6497
+ }
6498
+
6499
+ if (!cxxRecordReturnType->hasUserDeclaredCopyConstructor () &&
6500
+ !cxxRecordReturnType->hasUserDeclaredMoveConstructor () &&
6501
+ hasPointerInSubobjects (cxxRecordReturnType)) {
6502
+ return false ;
6503
+ }
6476
6504
}
6477
6505
}
6478
-
6479
- recordDecl = method->getParent ();
6480
- } else if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(decl)) {
6481
- recordDecl = cxxRecordDecl;
6482
- } else {
6483
- llvm_unreachable (" decl must be a C++ method or C++ record." );
6484
6506
}
6485
6507
6486
- auto semanticsKind = evaluateOrDefault (
6487
- evaluator, CxxRecordSemantics ({recordDecl, desc.ctx }), {});
6488
-
6489
- // Always unsafe.
6490
- if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation)
6491
- return false ;
6492
-
6493
- // Always OK.
6494
- if (semanticsKind == CxxRecordSemanticsKind::Reference)
6495
- return true ;
6496
-
6497
-
6498
- // All other record semantics kinds are some varient of an "owned" type, so
6499
- // dis-allow potential projections.
6500
- return cxxMethodIsSafe;
6508
+ // Otherwise, it's safe.
6509
+ return true ;
6501
6510
}
6502
6511
6503
6512
void swift::simple_display (llvm::raw_ostream &out,
0 commit comments