@@ -1406,10 +1406,10 @@ ClangImporter::create(ASTContext &ctx,
1406
1406
// Install a Clang module file extension to build Swift name lookup tables.
1407
1407
importer->Impl .Invocation ->getFrontendOpts ().ModuleFileExtensions .push_back (
1408
1408
std::make_shared<SwiftNameLookupExtension>(
1409
- importer->Impl .BridgingHeaderLookupTable ,
1410
- importer->Impl .LookupTables , importer-> Impl . SwiftContext ,
1409
+ importer->Impl .BridgingHeaderLookupTable , importer-> Impl . LookupTables ,
1410
+ importer->Impl .SwiftContext ,
1411
1411
importer->Impl .getBufferImporterForDiagnostics (),
1412
- importer->Impl .platformAvailability ));
1412
+ importer->Impl .platformAvailability , &importer-> Impl ));
1413
1413
1414
1414
// Create a compiler instance.
1415
1415
{
@@ -1557,7 +1557,7 @@ ClangImporter::create(ASTContext &ctx,
1557
1557
1558
1558
importer->Impl .nameImporter .reset (new NameImporter (
1559
1559
importer->Impl .SwiftContext , importer->Impl .platformAvailability ,
1560
- importer->Impl .getClangSema ()));
1560
+ importer->Impl .getClangSema (), &importer-> Impl ));
1561
1561
1562
1562
// FIXME: These decls are not being parsed correctly since (a) some of the
1563
1563
// callbacks are still being added, and (b) the logic to parse them has
@@ -7678,7 +7678,146 @@ bool importer::isForeignReferenceTypeWithoutImmortalAttrs(const clang::QualType
7678
7678
!hasImmortalAtts (pointeeType->getDecl ());
7679
7679
}
7680
7680
7681
+ static bool hasDiamondInheritanceRefType (const clang::CXXRecordDecl *decl) {
7682
+ if (!decl->hasDefinition () || decl->isDependentType ())
7683
+ return false ;
7684
+
7685
+ llvm::DenseSet<const clang::CXXRecordDecl *> seenBases;
7686
+ bool hasRefDiamond = false ;
7687
+
7688
+ decl->forallBases ([&](const clang::CXXRecordDecl *Base) {
7689
+ if (hasImportAsRefAttr (Base) && !seenBases.insert (Base).second &&
7690
+ !decl->isVirtuallyDerivedFrom (Base))
7691
+ hasRefDiamond = true ;
7692
+ return true ;
7693
+ });
7694
+
7695
+ return hasRefDiamond;
7696
+ }
7697
+
7698
+ // Returns the given declaration along with all its parent declarations that are
7699
+ // reference types.
7700
+ static llvm::SmallVector<const clang::RecordDecl *, 4 >
7701
+ getRefParentDecls (const clang::RecordDecl *decl, ASTContext &ctx,
7702
+ ClangImporter::Implementation *importerImpl) {
7703
+ assert (decl && " decl is null inside getRefParentDecls" );
7704
+
7705
+ llvm::SmallVector<const clang::RecordDecl *, 4 > matchingDecls;
7706
+
7707
+ if (hasImportAsRefAttr (decl))
7708
+ matchingDecls.push_back (decl);
7709
+
7710
+ if (const auto *cxxRecordDecl = llvm::dyn_cast<clang::CXXRecordDecl>(decl)) {
7711
+ if (!cxxRecordDecl->hasDefinition ())
7712
+ return matchingDecls;
7713
+ if (hasDiamondInheritanceRefType (cxxRecordDecl)) {
7714
+ if (importerImpl) {
7715
+ if (!importerImpl->DiagnosedCxxRefDecls .count (decl)) {
7716
+ HeaderLoc loc (decl->getLocation ());
7717
+ importerImpl->diagnose (loc, diag::cant_infer_frt_in_cxx_inheritance,
7718
+ decl);
7719
+ importerImpl->DiagnosedCxxRefDecls .insert (decl);
7720
+ }
7721
+ } else {
7722
+ ctx.Diags .diagnose ({}, diag::cant_infer_frt_in_cxx_inheritance, decl);
7723
+ assert (false && " nullpointer passeed for importerImpl when calling "
7724
+ " getRefParentOrDiag" );
7725
+ }
7726
+ return matchingDecls;
7727
+ }
7728
+ cxxRecordDecl->forallBases ([&](const clang::CXXRecordDecl *baseDecl) {
7729
+ if (hasImportAsRefAttr (baseDecl))
7730
+ matchingDecls.push_back (baseDecl);
7731
+ return true ;
7732
+ });
7733
+ }
7734
+
7735
+ return matchingDecls;
7736
+ }
7737
+
7738
+ static llvm::SmallVector<ValueDecl *, 1 >
7739
+ getValueDeclsForName (const clang::Decl *decl, ASTContext &ctx, StringRef name) {
7740
+ llvm::SmallVector<ValueDecl *, 1 > results;
7741
+ auto *clangMod = decl->getOwningModule ();
7742
+ if (clangMod && clangMod->isSubModule ())
7743
+ clangMod = clangMod->getTopLevelModule ();
7744
+ if (clangMod) {
7745
+ auto parentModule =
7746
+ ctx.getClangModuleLoader ()->getWrapperForModule (clangMod);
7747
+ ctx.lookupInModule (parentModule, name, results);
7748
+ } else {
7749
+ // There is no Clang module for this declaration, so perform lookup from
7750
+ // the main module. This will find declarations from the bridging header.
7751
+ namelookup::lookupInModule (
7752
+ ctx.MainModule , ctx.getIdentifier (name), results,
7753
+ NLKind::UnqualifiedLookup, namelookup::ResolutionKind::Overloadable,
7754
+ ctx.MainModule , SourceLoc (), NL_UnqualifiedDefault);
7755
+
7756
+ // Filter out any declarations that didn't come from Clang.
7757
+ auto newEnd =
7758
+ std::remove_if (results.begin (), results.end (),
7759
+ [&](ValueDecl *decl) { return !decl->getClangDecl (); });
7760
+ results.erase (newEnd, results.end ());
7761
+ }
7762
+ return results;
7763
+ }
7764
+
7765
+ static const clang::RecordDecl *
7766
+ getRefParentOrDiag (const clang::RecordDecl *decl, ASTContext &ctx,
7767
+ ClangImporter::Implementation *importerImpl) {
7768
+ auto refParentDecls = getRefParentDecls (decl, ctx, importerImpl);
7769
+ if (refParentDecls.empty ())
7770
+ return nullptr ;
7771
+
7772
+ std::unordered_set<ValueDecl *> uniqueRetainDecls{}, uniqueReleaseDecls{};
7773
+ constexpr StringRef retainPrefix = " retain:" ;
7774
+ constexpr StringRef releasePrefix = " release:" ;
7775
+
7776
+ for (const auto *refParentDecl : refParentDecls) {
7777
+ assert (refParentDecl && " refParentDecl is null inside getRefParentOrDiag" );
7778
+ for (const auto *attr : refParentDecl->getAttrs ()) {
7779
+ if (const auto swiftAttr = llvm::dyn_cast<clang::SwiftAttrAttr>(attr)) {
7780
+ const auto &attribute = swiftAttr->getAttribute ();
7781
+ llvm::SmallVector<ValueDecl *, 1 > valueDecls;
7782
+ if (attribute.starts_with (retainPrefix)) {
7783
+ auto name = attribute.drop_front (retainPrefix.size ()).str ();
7784
+ valueDecls = getValueDeclsForName (decl, ctx, name);
7785
+ uniqueRetainDecls.insert (valueDecls.begin (), valueDecls.end ());
7786
+ } else if (attribute.starts_with (releasePrefix)) {
7787
+ auto name = attribute.drop_front (releasePrefix.size ()).str ();
7788
+ valueDecls = getValueDeclsForName (decl, ctx, name);
7789
+ uniqueReleaseDecls.insert (valueDecls.begin (), valueDecls.end ());
7790
+ }
7791
+ }
7792
+ }
7793
+ }
7794
+
7795
+ // Ensure that exactly one unique retain function and one unique release
7796
+ // function are found.
7797
+ if (uniqueRetainDecls.size () != 1 || uniqueReleaseDecls.size () != 1 ) {
7798
+ if (importerImpl) {
7799
+ if (!importerImpl->DiagnosedCxxRefDecls .count (decl)) {
7800
+ HeaderLoc loc (decl->getLocation ());
7801
+ importerImpl->diagnose (loc, diag::cant_infer_frt_in_cxx_inheritance,
7802
+ decl);
7803
+ importerImpl->DiagnosedCxxRefDecls .insert (decl);
7804
+ }
7805
+ } else {
7806
+ ctx.Diags .diagnose ({}, diag::cant_infer_frt_in_cxx_inheritance, decl);
7807
+ assert (false && " nullpointer passed for importerImpl when calling "
7808
+ " getRefParentOrDiag" );
7809
+ }
7810
+ return nullptr ;
7811
+ }
7812
+
7813
+ return refParentDecls.front ();
7814
+ }
7815
+
7681
7816
// Is this a pointer to a foreign reference type.
7817
+ // TODO: We need to review functions like this to ensure that
7818
+ // CxxRecordSemantics::evaluate is consistently invoked wherever we need to
7819
+ // determine whether a C++ type qualifies as a foreign reference type
7820
+ // rdar://145184659
7682
7821
static bool isForeignReferenceType (const clang::QualType type) {
7683
7822
if (!type->isPointerType ())
7684
7823
return false ;
@@ -7927,10 +8066,10 @@ CxxRecordSemanticsKind
7927
8066
CxxRecordSemantics::evaluate (Evaluator &evaluator,
7928
8067
CxxRecordSemanticsDescriptor desc) const {
7929
8068
const auto *decl = desc.decl ;
7930
-
7931
- if (hasImportAsRefAttr (decl)) {
8069
+ ClangImporter::Implementation *importerImpl = desc.importerImpl ;
8070
+ if (hasImportAsRefAttr (decl) ||
8071
+ getRefParentOrDiag (decl, desc.ctx , importerImpl))
7932
8072
return CxxRecordSemanticsKind::Reference;
7933
- }
7934
8073
7935
8074
auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl);
7936
8075
if (!cxxDecl) {
@@ -7943,15 +8082,16 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
7943
8082
if (!hasDestroyTypeOperations (cxxDecl) ||
7944
8083
(!hasCopyTypeOperations (cxxDecl) && !hasMoveTypeOperations (cxxDecl))) {
7945
8084
if (desc.shouldDiagnoseLifetimeOperations ) {
8085
+ HeaderLoc loc (decl->getLocation ());
7946
8086
if (hasUnsafeAPIAttr (cxxDecl))
7947
- desc. ctx . Diags . diagnose ({} , diag::api_pattern_attr_ignored,
7948
- " import_unsafe" , decl->getNameAsString ());
8087
+ importerImpl-> diagnose (loc , diag::api_pattern_attr_ignored,
8088
+ " import_unsafe" , decl->getNameAsString ());
7949
8089
if (hasOwnedValueAttr (cxxDecl))
7950
- desc. ctx . Diags . diagnose ({} , diag::api_pattern_attr_ignored,
7951
- " import_owned" , decl->getNameAsString ());
8090
+ importerImpl-> diagnose (loc , diag::api_pattern_attr_ignored,
8091
+ " import_owned" , decl->getNameAsString ());
7952
8092
if (hasIteratorAPIAttr (cxxDecl))
7953
- desc. ctx . Diags . diagnose ({} , diag::api_pattern_attr_ignored,
7954
- " import_iterator" , decl->getNameAsString ());
8093
+ importerImpl-> diagnose (loc , diag::api_pattern_attr_ignored,
8094
+ " import_iterator" , decl->getNameAsString ());
7955
8095
}
7956
8096
7957
8097
return CxxRecordSemanticsKind::MissingLifetimeOperation;
@@ -8158,6 +8298,12 @@ CustomRefCountingOperationResult CustomRefCountingOperation::evaluate(
8158
8298
: " release:" ;
8159
8299
8160
8300
auto decl = cast<clang::RecordDecl>(swiftDecl->getClangDecl ());
8301
+
8302
+ if (!hasImportAsRefAttr (decl)) {
8303
+ if (auto parentRefDecl = getRefParentOrDiag (decl, ctx, nullptr ))
8304
+ decl = parentRefDecl;
8305
+ }
8306
+
8161
8307
if (!decl->hasAttrs ())
8162
8308
return {CustomRefCountingOperationResult::noAttribute, nullptr , " " };
8163
8309
@@ -8184,27 +8330,8 @@ CustomRefCountingOperationResult CustomRefCountingOperation::evaluate(
8184
8330
if (name == " immortal" )
8185
8331
return {CustomRefCountingOperationResult::immortal, nullptr , name};
8186
8332
8187
- llvm::SmallVector<ValueDecl *, 1 > results;
8188
- auto *clangMod = swiftDecl->getClangDecl ()->getOwningModule ();
8189
- if (clangMod && clangMod->isSubModule ())
8190
- clangMod = clangMod->getTopLevelModule ();
8191
- if (clangMod) {
8192
- auto parentModule = ctx.getClangModuleLoader ()->getWrapperForModule (clangMod);
8193
- ctx.lookupInModule (parentModule, name, results);
8194
- } else {
8195
- // There is no Clang module for this declaration, so perform lookup from
8196
- // the main module. This will find declarations from the bridging header.
8197
- namelookup::lookupInModule (
8198
- ctx.MainModule , ctx.getIdentifier (name), results,
8199
- NLKind::UnqualifiedLookup, namelookup::ResolutionKind::Overloadable,
8200
- ctx.MainModule , SourceLoc (), NL_UnqualifiedDefault);
8201
-
8202
- // Filter out any declarations that didn't come from Clang.
8203
- auto newEnd = std::remove_if (results.begin (), results.end (), [&](ValueDecl *decl) {
8204
- return !decl->getClangDecl ();
8205
- });
8206
- results.erase (newEnd, results.end ());
8207
- }
8333
+ llvm::SmallVector<ValueDecl *, 1 > results =
8334
+ getValueDeclsForName (swiftDecl->getClangDecl (), ctx, name);
8208
8335
if (results.size () == 1 )
8209
8336
return {CustomRefCountingOperationResult::foundOperation, results.front (),
8210
8337
name};
0 commit comments