mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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: #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
This commit is contained in:
committed by
Gabor Horvath
parent
7c12be865e
commit
b51b58db30
@@ -216,6 +216,9 @@ public:
|
|||||||
DeclContext *newContext,
|
DeclContext *newContext,
|
||||||
ClangInheritanceInfo inheritance) = 0;
|
ClangInheritanceInfo inheritance) = 0;
|
||||||
|
|
||||||
|
/// Returnes the original method if \param decl is a clone from a base class
|
||||||
|
virtual ValueDecl *getOriginalForClonedMember(const ValueDecl *decl) = 0;
|
||||||
|
|
||||||
/// Emits diagnostics for any declarations named name
|
/// Emits diagnostics for any declarations named name
|
||||||
/// whose direct declaration context is a TU.
|
/// whose direct declaration context is a TU.
|
||||||
virtual void diagnoseTopLevelValue(const DeclName &name) = 0;
|
virtual void diagnoseTopLevelValue(const DeclName &name) = 0;
|
||||||
|
|||||||
@@ -655,6 +655,8 @@ public:
|
|||||||
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
|
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
|
||||||
ClangInheritanceInfo inheritance) override;
|
ClangInheritanceInfo inheritance) override;
|
||||||
|
|
||||||
|
ValueDecl *getOriginalForClonedMember(const ValueDecl *decl) override;
|
||||||
|
|
||||||
/// Emits diagnostics for any declarations named name
|
/// Emits diagnostics for any declarations named name
|
||||||
/// whose direct declaration context is a TU.
|
/// whose direct declaration context is a TU.
|
||||||
void diagnoseTopLevelValue(const DeclName &name) override;
|
void diagnoseTopLevelValue(const DeclName &name) override;
|
||||||
|
|||||||
@@ -906,6 +906,17 @@ static ModuleDecl *getModuleContextForNameLookupForCxxDecl(const Decl *decl) {
|
|||||||
if (!ctx.LangOpts.EnableCXXInterop)
|
if (!ctx.LangOpts.EnableCXXInterop)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// When we clone members for base classes the cloned members have no
|
||||||
|
// corresponding Clang nodes. Look up the original imported declaration to
|
||||||
|
// figure out what Clang module does the cloned member originate from.
|
||||||
|
bool isClonedMember = false;
|
||||||
|
if (auto VD = dyn_cast<ValueDecl>(decl))
|
||||||
|
if (auto loader = ctx.getClangModuleLoader())
|
||||||
|
if (auto original = loader->getOriginalForClonedMember(VD)) {
|
||||||
|
isClonedMember = true;
|
||||||
|
decl = original;
|
||||||
|
}
|
||||||
|
|
||||||
if (!decl->hasClangNode())
|
if (!decl->hasClangNode())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@@ -913,8 +924,11 @@ static ModuleDecl *getModuleContextForNameLookupForCxxDecl(const Decl *decl) {
|
|||||||
|
|
||||||
// We only need to look for the real parent module when the existing parent
|
// We only need to look for the real parent module when the existing parent
|
||||||
// is the imported header module.
|
// is the imported header module.
|
||||||
if (!parentModule->isClangHeaderImportModule())
|
if (!parentModule->isClangHeaderImportModule()) {
|
||||||
|
if (isClonedMember)
|
||||||
|
return parentModule;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto clangModule = decl->getClangDecl()->getOwningModule();
|
auto clangModule = decl->getClangDecl()->getOwningModule();
|
||||||
if (!clangModule)
|
if (!clangModule)
|
||||||
|
|||||||
@@ -5516,10 +5516,11 @@ const clang::CXXMethodDecl *getCalledBaseCxxMethod(FuncDecl *baseMember) {
|
|||||||
|
|
||||||
// Construct a Swift method that represents the synthesized C++ method
|
// Construct a Swift method that represents the synthesized C++ method
|
||||||
// that invokes the base C++ method.
|
// that invokes the base C++ method.
|
||||||
FuncDecl *synthesizeBaseFunctionDeclCall(ClangImporter &impl, ASTContext &ctx,
|
static FuncDecl *synthesizeBaseFunctionDeclCall(ClangImporter &impl,
|
||||||
NominalTypeDecl *derivedStruct,
|
ASTContext &ctx,
|
||||||
NominalTypeDecl *baseStruct,
|
NominalTypeDecl *derivedStruct,
|
||||||
FuncDecl *baseMember) {
|
NominalTypeDecl *baseStruct,
|
||||||
|
FuncDecl *baseMember) {
|
||||||
auto *cxxMethod = getCalledBaseCxxMethod(baseMember);
|
auto *cxxMethod = getCalledBaseCxxMethod(baseMember);
|
||||||
if (!cxxMethod)
|
if (!cxxMethod)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -7661,11 +7662,26 @@ ValueDecl *ClangImporter::Implementation::importBaseMemberDecl(
|
|||||||
if (known == clonedBaseMembers.end()) {
|
if (known == clonedBaseMembers.end()) {
|
||||||
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext, inheritance);
|
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext, inheritance);
|
||||||
known = clonedBaseMembers.insert({key, cloned}).first;
|
known = clonedBaseMembers.insert({key, cloned}).first;
|
||||||
|
clonedMembers.insert(std::make_pair(cloned, decl));
|
||||||
}
|
}
|
||||||
|
|
||||||
return known->second;
|
return known->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueDecl *ClangImporter::Implementation::getOriginalForClonedMember(
|
||||||
|
const ValueDecl *decl) {
|
||||||
|
// If this is a cloned decl, we don't want to reclone it
|
||||||
|
// Otherwise, we may end up with multiple copies of the same method
|
||||||
|
if (!decl->hasClangNode()) {
|
||||||
|
// Skip decls with a clang node as those will never be a clone
|
||||||
|
auto result = clonedMembers.find(decl);
|
||||||
|
if (result != clonedMembers.end())
|
||||||
|
return result->getSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
size_t ClangImporter::Implementation::getImportedBaseMemberDeclArity(
|
size_t ClangImporter::Implementation::getImportedBaseMemberDeclArity(
|
||||||
const ValueDecl *valueDecl) {
|
const ValueDecl *valueDecl) {
|
||||||
if (auto *func = dyn_cast<FuncDecl>(valueDecl)) {
|
if (auto *func = dyn_cast<FuncDecl>(valueDecl)) {
|
||||||
@@ -7682,6 +7698,10 @@ ClangImporter::importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
|
|||||||
return Impl.importBaseMemberDecl(decl, newContext, inheritance);
|
return Impl.importBaseMemberDecl(decl, newContext, inheritance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueDecl *ClangImporter::getOriginalForClonedMember(const ValueDecl *decl) {
|
||||||
|
return Impl.getOriginalForClonedMember(decl);
|
||||||
|
}
|
||||||
|
|
||||||
void ClangImporter::diagnoseTopLevelValue(const DeclName &name) {
|
void ClangImporter::diagnoseTopLevelValue(const DeclName &name) {
|
||||||
Impl.diagnoseTopLevelValue(name);
|
Impl.diagnoseTopLevelValue(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -688,6 +688,9 @@ private:
|
|||||||
llvm::DenseMap<std::pair<ValueDecl *, DeclContext *>, ValueDecl *>
|
llvm::DenseMap<std::pair<ValueDecl *, DeclContext *>, ValueDecl *>
|
||||||
clonedBaseMembers;
|
clonedBaseMembers;
|
||||||
|
|
||||||
|
// Map all cloned methods back to the original member
|
||||||
|
llvm::DenseMap<ValueDecl *, ValueDecl *> clonedMembers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
llvm::DenseMap<const clang::ParmVarDecl*, FuncDecl*> defaultArgGenerators;
|
llvm::DenseMap<const clang::ParmVarDecl*, FuncDecl*> defaultArgGenerators;
|
||||||
|
|
||||||
@@ -696,6 +699,8 @@ public:
|
|||||||
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
|
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
|
||||||
ClangInheritanceInfo inheritance);
|
ClangInheritanceInfo inheritance);
|
||||||
|
|
||||||
|
ValueDecl *getOriginalForClonedMember(const ValueDecl *decl);
|
||||||
|
|
||||||
static size_t getImportedBaseMemberDeclArity(const ValueDecl *valueDecl);
|
static size_t getImportedBaseMemberDeclArity(const ValueDecl *valueDecl);
|
||||||
|
|
||||||
// Cache for already-specialized function templates and any thunks they may
|
// Cache for already-specialized function templates and any thunks they may
|
||||||
|
|||||||
@@ -16,3 +16,12 @@ struct IIOne : IOne {
|
|||||||
struct IIIOne : IIOne {
|
struct IIIOne : IIOne {
|
||||||
int methodIII(void) const { return -111; }
|
int methodIII(void) const { return -111; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Base {
|
||||||
|
public:
|
||||||
|
bool baseMethod() const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Bar {
|
||||||
|
class Derived : public Base {};
|
||||||
|
} // namespace Bar
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -cxx-interoperability-mode=default)
|
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -cxx-interoperability-mode=default)
|
||||||
//
|
//
|
||||||
// REQUIRES: executable_test
|
// REQUIRES: executable_test
|
||||||
|
|
||||||
import InheritedLookup
|
import InheritedLookup
|
||||||
import StdlibUnittest
|
import StdlibUnittest
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -cxx-interoperability-mode=default -enable-upcoming-feature MemberImportVisibility)
|
||||||
|
//
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
// REQUIRES: swift_feature_MemberImportVisibility
|
||||||
|
|
||||||
|
import InheritedLookup
|
||||||
|
import StdlibUnittest
|
||||||
|
|
||||||
|
var InheritedMemberTestSuite = TestSuite("Test if inherited lookup works")
|
||||||
|
|
||||||
|
extension Bar.Derived {
|
||||||
|
public func callBase() {
|
||||||
|
let _ = baseMethod()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InheritedMemberTestSuite.test("Look up base methods from extensions") {
|
||||||
|
let a = Bar.Derived()
|
||||||
|
a.callBase()
|
||||||
|
}
|
||||||
|
|
||||||
|
runAllTests()
|
||||||
Reference in New Issue
Block a user