Skip to content

Commit b51b58d

Browse files
Xazax-hunGabor Horvath
authored andcommitted
[6.2][cxx-interop] Fix unqualified name lookup failure
Explanation: C++ interop synthesizes certain forwarding functions in an _ObjC module. This confuses MemberImportVisibility. This patch adds logic to work this around by keeping a mapping between the synthesized and the original function and looks up where the synthesized functions belong to based on the original functions' parent module. Scope: C++ forward interop when MemberImportVisibility is enabled. Issues: rdar://154887575 Original PRs: swiftlang#82840 Risk: Low, a narrow change makes getModuleContextForNameLookupForCxxDecl more precise, and it is only used with MemberImportVisibility. Testing: Added a compiler test. Reviewers: @egorzhdan, @tshortli, @hnrklssn
1 parent 7c12be8 commit b51b58d

File tree

8 files changed

+81
-5
lines changed

8 files changed

+81
-5
lines changed

include/swift/AST/ClangModuleLoader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ class ClangModuleLoader : public ModuleLoader {
216216
DeclContext *newContext,
217217
ClangInheritanceInfo inheritance) = 0;
218218

219+
/// Returnes the original method if \param decl is a clone from a base class
220+
virtual ValueDecl *getOriginalForClonedMember(const ValueDecl *decl) = 0;
221+
219222
/// Emits diagnostics for any declarations named name
220223
/// whose direct declaration context is a TU.
221224
virtual void diagnoseTopLevelValue(const DeclName &name) = 0;

include/swift/ClangImporter/ClangImporter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,8 @@ class ClangImporter final : public ClangModuleLoader {
655655
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
656656
ClangInheritanceInfo inheritance) override;
657657

658+
ValueDecl *getOriginalForClonedMember(const ValueDecl *decl) override;
659+
658660
/// Emits diagnostics for any declarations named name
659661
/// whose direct declaration context is a TU.
660662
void diagnoseTopLevelValue(const DeclName &name) override;

lib/AST/Decl.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,15 +906,29 @@ static ModuleDecl *getModuleContextForNameLookupForCxxDecl(const Decl *decl) {
906906
if (!ctx.LangOpts.EnableCXXInterop)
907907
return nullptr;
908908

909+
// When we clone members for base classes the cloned members have no
910+
// corresponding Clang nodes. Look up the original imported declaration to
911+
// figure out what Clang module does the cloned member originate from.
912+
bool isClonedMember = false;
913+
if (auto VD = dyn_cast<ValueDecl>(decl))
914+
if (auto loader = ctx.getClangModuleLoader())
915+
if (auto original = loader->getOriginalForClonedMember(VD)) {
916+
isClonedMember = true;
917+
decl = original;
918+
}
919+
909920
if (!decl->hasClangNode())
910921
return nullptr;
911922

912923
auto parentModule = decl->getModuleContext();
913924

914925
// We only need to look for the real parent module when the existing parent
915926
// is the imported header module.
916-
if (!parentModule->isClangHeaderImportModule())
927+
if (!parentModule->isClangHeaderImportModule()) {
928+
if (isClonedMember)
929+
return parentModule;
917930
return nullptr;
931+
}
918932

919933
auto clangModule = decl->getClangDecl()->getOwningModule();
920934
if (!clangModule)

lib/ClangImporter/ClangImporter.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5516,10 +5516,11 @@ const clang::CXXMethodDecl *getCalledBaseCxxMethod(FuncDecl *baseMember) {
55165516

55175517
// Construct a Swift method that represents the synthesized C++ method
55185518
// that invokes the base C++ method.
5519-
FuncDecl *synthesizeBaseFunctionDeclCall(ClangImporter &impl, ASTContext &ctx,
5520-
NominalTypeDecl *derivedStruct,
5521-
NominalTypeDecl *baseStruct,
5522-
FuncDecl *baseMember) {
5519+
static FuncDecl *synthesizeBaseFunctionDeclCall(ClangImporter &impl,
5520+
ASTContext &ctx,
5521+
NominalTypeDecl *derivedStruct,
5522+
NominalTypeDecl *baseStruct,
5523+
FuncDecl *baseMember) {
55235524
auto *cxxMethod = getCalledBaseCxxMethod(baseMember);
55245525
if (!cxxMethod)
55255526
return nullptr;
@@ -7661,11 +7662,26 @@ ValueDecl *ClangImporter::Implementation::importBaseMemberDecl(
76617662
if (known == clonedBaseMembers.end()) {
76627663
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext, inheritance);
76637664
known = clonedBaseMembers.insert({key, cloned}).first;
7665+
clonedMembers.insert(std::make_pair(cloned, decl));
76647666
}
76657667

76667668
return known->second;
76677669
}
76687670

7671+
ValueDecl *ClangImporter::Implementation::getOriginalForClonedMember(
7672+
const ValueDecl *decl) {
7673+
// If this is a cloned decl, we don't want to reclone it
7674+
// Otherwise, we may end up with multiple copies of the same method
7675+
if (!decl->hasClangNode()) {
7676+
// Skip decls with a clang node as those will never be a clone
7677+
auto result = clonedMembers.find(decl);
7678+
if (result != clonedMembers.end())
7679+
return result->getSecond();
7680+
}
7681+
7682+
return nullptr;
7683+
}
7684+
76697685
size_t ClangImporter::Implementation::getImportedBaseMemberDeclArity(
76707686
const ValueDecl *valueDecl) {
76717687
if (auto *func = dyn_cast<FuncDecl>(valueDecl)) {
@@ -7682,6 +7698,10 @@ ClangImporter::importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
76827698
return Impl.importBaseMemberDecl(decl, newContext, inheritance);
76837699
}
76847700

7701+
ValueDecl *ClangImporter::getOriginalForClonedMember(const ValueDecl *decl) {
7702+
return Impl.getOriginalForClonedMember(decl);
7703+
}
7704+
76857705
void ClangImporter::diagnoseTopLevelValue(const DeclName &name) {
76867706
Impl.diagnoseTopLevelValue(name);
76877707
}

lib/ClangImporter/ImporterImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
688688
llvm::DenseMap<std::pair<ValueDecl *, DeclContext *>, ValueDecl *>
689689
clonedBaseMembers;
690690

691+
// Map all cloned methods back to the original member
692+
llvm::DenseMap<ValueDecl *, ValueDecl *> clonedMembers;
693+
691694
public:
692695
llvm::DenseMap<const clang::ParmVarDecl*, FuncDecl*> defaultArgGenerators;
693696

@@ -696,6 +699,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
696699
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
697700
ClangInheritanceInfo inheritance);
698701

702+
ValueDecl *getOriginalForClonedMember(const ValueDecl *decl);
703+
699704
static size_t getImportedBaseMemberDeclArity(const ValueDecl *valueDecl);
700705

701706
// Cache for already-specialized function templates and any thunks they may

test/Interop/Cxx/class/inheritance/Inputs/inherited-lookup.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,12 @@ struct IIOne : IOne {
1616
struct IIIOne : IIOne {
1717
int methodIII(void) const { return -111; }
1818
};
19+
20+
class Base {
21+
public:
22+
bool baseMethod() const { return true; }
23+
};
24+
25+
namespace Bar {
26+
class Derived : public Base {};
27+
} // namespace Bar

test/Interop/Cxx/class/inheritance/inherited-lookup-executable.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -cxx-interoperability-mode=default)
22
//
33
// REQUIRES: executable_test
4+
45
import InheritedLookup
56
import StdlibUnittest
67

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -cxx-interoperability-mode=default -enable-upcoming-feature MemberImportVisibility)
2+
//
3+
// REQUIRES: executable_test
4+
// REQUIRES: swift_feature_MemberImportVisibility
5+
6+
import InheritedLookup
7+
import StdlibUnittest
8+
9+
var InheritedMemberTestSuite = TestSuite("Test if inherited lookup works")
10+
11+
extension Bar.Derived {
12+
public func callBase() {
13+
let _ = baseMethod()
14+
}
15+
}
16+
17+
InheritedMemberTestSuite.test("Look up base methods from extensions") {
18+
let a = Bar.Derived()
19+
a.callBase()
20+
}
21+
22+
runAllTests()

0 commit comments

Comments
 (0)