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