@@ -6312,6 +6312,19 @@ static bool hasImportAsRefAttr(const clang::RecordDecl *decl) {
6312
6312
});
6313
6313
}
6314
6314
6315
+ // Is this a pointer to a foreign reference type.
6316
+ static bool isForeignReferenceType (const clang::QualType type) {
6317
+ if (!type->isPointerType ())
6318
+ return false ;
6319
+
6320
+ auto pointeeType =
6321
+ dyn_cast<clang::RecordType>(type->getPointeeType ().getCanonicalType ());
6322
+ if (pointeeType == nullptr )
6323
+ return false ;
6324
+
6325
+ return hasImportAsRefAttr (pointeeType->getDecl ());
6326
+ }
6327
+
6315
6328
static bool hasOwnedValueAttr (const clang::RecordDecl *decl) {
6316
6329
// Hard-coded special cases from the standard library (this will go away once
6317
6330
// API notes support namespaces).
@@ -6474,14 +6487,16 @@ CxxRecordSemanticsKind
6474
6487
CxxRecordSemantics::evaluate (Evaluator &evaluator,
6475
6488
CxxRecordSemanticsDescriptor desc) const {
6476
6489
const auto *decl = desc.decl ;
6490
+ auto &clangSema = desc.ctx .getClangModuleLoader ()->getClangSema ();
6477
6491
6478
6492
if (hasImportAsRefAttr (decl)) {
6479
6493
return CxxRecordSemanticsKind::Reference;
6480
6494
}
6481
6495
6482
6496
auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl);
6483
- if (!cxxDecl)
6497
+ if (!cxxDecl) {
6484
6498
return CxxRecordSemanticsKind::Trivial;
6499
+ }
6485
6500
6486
6501
if (!hasRequiredValueTypeOperations (cxxDecl)) {
6487
6502
if (hasUnsafeAPIAttr (cxxDecl))
@@ -6523,58 +6538,52 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
6523
6538
bool IsSafeUseOfCxxDecl::evaluate (Evaluator &evaluator,
6524
6539
SafeUseOfCxxDeclDescriptor desc) const {
6525
6540
const clang::Decl *decl = desc.decl ;
6526
- const clang::CXXRecordDecl *recordDecl = nullptr ;
6527
- bool cxxMethodIsSafe = true ;
6528
6541
6529
6542
if (auto method = dyn_cast<clang::CXXMethodDecl>(decl)) {
6543
+ // The user explicitly asked us to import this method.
6530
6544
if (hasUnsafeAPIAttr (method))
6531
6545
return true ;
6532
6546
6547
+ // If it's a static method, it cannot project anything. It's fine.
6533
6548
if (method->isOverloadedOperator () || method->isStatic () ||
6534
6549
isa<clang::CXXConstructorDecl>(decl))
6535
6550
return true ;
6536
6551
6552
+ if (isForeignReferenceType (method->getReturnType ()))
6553
+ return true ;
6554
+
6555
+ // If it returns a pointer or reference, that's a projection.
6537
6556
if (method->getReturnType ()->isPointerType () ||
6538
6557
method->getReturnType ()->isReferenceType ())
6539
- cxxMethodIsSafe = false ;
6558
+ return false ;
6540
6559
6560
+ // Try to figure out the semantics of the return type. If it's a
6561
+ // pointer/iterator, it's unsafe.
6541
6562
if (auto returnType = dyn_cast<clang::RecordType>(
6542
6563
method->getReturnType ().getCanonicalType ())) {
6543
6564
if (auto cxxRecordReturnType =
6544
6565
dyn_cast<clang::CXXRecordDecl>(returnType->getDecl ())) {
6545
- auto semanticsKind = evaluateOrDefault (
6546
- evaluator, CxxRecordSemantics ({cxxRecordReturnType, desc.ctx }), {});
6547
-
6548
- if (semanticsKind == CxxRecordSemanticsKind::UnsafePointerMember ||
6549
- // Pretend all methods that return iterators are unsafe so protocol
6550
- // conformances work.
6551
- semanticsKind == CxxRecordSemanticsKind::Iterator)
6552
- cxxMethodIsSafe = false ;
6566
+ if (hasIteratorAPIAttr (cxxRecordReturnType) ||
6567
+ isIterator (cxxRecordReturnType)) {
6568
+ return false ;
6569
+ }
6570
+
6571
+ // Mark this as safe to help our diganostics down the road.
6572
+ if (!cxxRecordReturnType->getDefinition ()) {
6573
+ return true ;
6574
+ }
6575
+
6576
+ if (!cxxRecordReturnType->hasUserDeclaredCopyConstructor () &&
6577
+ !cxxRecordReturnType->hasUserDeclaredMoveConstructor () &&
6578
+ hasPointerInSubobjects (cxxRecordReturnType)) {
6579
+ return false ;
6580
+ }
6553
6581
}
6554
6582
}
6555
-
6556
- recordDecl = method->getParent ();
6557
- } else if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(decl)) {
6558
- recordDecl = cxxRecordDecl;
6559
- } else {
6560
- llvm_unreachable (" decl must be a C++ method or C++ record." );
6561
6583
}
6562
6584
6563
- auto semanticsKind = evaluateOrDefault (
6564
- evaluator, CxxRecordSemantics ({recordDecl, desc.ctx }), {});
6565
-
6566
- // Always unsafe.
6567
- if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation)
6568
- return false ;
6569
-
6570
- // Always OK.
6571
- if (semanticsKind == CxxRecordSemanticsKind::Reference)
6572
- return true ;
6573
-
6574
-
6575
- // All other record semantics kinds are some varient of an "owned" type, so
6576
- // dis-allow potential projections.
6577
- return cxxMethodIsSafe;
6585
+ // Otherwise, it's safe.
6586
+ return true ;
6578
6587
}
6579
6588
6580
6589
void swift::simple_display (llvm::raw_ostream &out,
0 commit comments