mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[cxx-interop] Clang member lookup should not look into Swift extensions
Calling `NominalTypeDecl::lookupDirect` triggers deserialization of Swift extensions for the type. `ClangRecordMemberLookup` shouldn't assume it is allowed to deserialize Swift extensions for the given C++ type: there might be extensions which reference the module that is currently being imported, which causes circular request dependency errors.
This commit is contained in:
@@ -184,6 +184,11 @@ public:
|
|||||||
/// Imports a clang decl directly, rather than looking up its name.
|
/// Imports a clang decl directly, rather than looking up its name.
|
||||||
virtual Decl *importDeclDirectly(const clang::NamedDecl *decl) = 0;
|
virtual Decl *importDeclDirectly(const clang::NamedDecl *decl) = 0;
|
||||||
|
|
||||||
|
/// Imports a clang decl from a base class, cloning it for \param newContext
|
||||||
|
/// if it wasn't cloned for this specific context before.
|
||||||
|
virtual ValueDecl *importBaseMemberDecl(ValueDecl *decl,
|
||||||
|
DeclContext *newContext) = 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;
|
||||||
|
|||||||
@@ -531,6 +531,9 @@ public:
|
|||||||
/// Imports a clang decl directly, rather than looking up it's name.
|
/// Imports a clang decl directly, rather than looking up it's name.
|
||||||
Decl *importDeclDirectly(const clang::NamedDecl *decl) override;
|
Decl *importDeclDirectly(const clang::NamedDecl *decl) override;
|
||||||
|
|
||||||
|
ValueDecl *importBaseMemberDecl(ValueDecl *decl,
|
||||||
|
DeclContext *newContext) 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;
|
||||||
|
|||||||
@@ -4935,11 +4935,12 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
|
|||||||
|
|
||||||
// Find the results that are actually a member of "recordDecl".
|
// Find the results that are actually a member of "recordDecl".
|
||||||
TinyPtrVector<ValueDecl *> result;
|
TinyPtrVector<ValueDecl *> result;
|
||||||
|
ClangModuleLoader *clangModuleLoader = ctx.getClangModuleLoader();
|
||||||
for (auto found : allResults) {
|
for (auto found : allResults) {
|
||||||
auto named = found.get<clang::NamedDecl *>();
|
auto named = found.get<clang::NamedDecl *>();
|
||||||
if (dyn_cast<clang::Decl>(named->getDeclContext()) ==
|
if (dyn_cast<clang::Decl>(named->getDeclContext()) ==
|
||||||
recordDecl->getClangDecl()) {
|
recordDecl->getClangDecl()) {
|
||||||
if (auto import = ctx.getClangModuleLoader()->importDeclDirectly(named))
|
if (auto import = clangModuleLoader->importDeclDirectly(named))
|
||||||
result.push_back(cast<ValueDecl>(import));
|
result.push_back(cast<ValueDecl>(import));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4955,16 +4956,32 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto *baseRecord = baseType->getAs<clang::RecordType>()->getDecl();
|
auto *baseRecord = baseType->getAs<clang::RecordType>()->getDecl();
|
||||||
if (auto import =
|
if (auto import = clangModuleLoader->importDeclDirectly(baseRecord)) {
|
||||||
ctx.getClangModuleLoader()->importDeclDirectly(baseRecord)) {
|
|
||||||
// If we are looking up the base class, go no further. We will have
|
// If we are looking up the base class, go no further. We will have
|
||||||
// already found it during the other lookup.
|
// already found it during the other lookup.
|
||||||
if (cast<ValueDecl>(import)->getName() == name)
|
if (cast<ValueDecl>(import)->getName() == name)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto baseResults = cast<NominalTypeDecl>(import)->lookupDirect(name);
|
// Add Clang members that are imported lazily.
|
||||||
|
auto baseResults = evaluateOrDefault(
|
||||||
|
ctx.evaluator,
|
||||||
|
ClangRecordMemberLookup({cast<NominalTypeDecl>(import), name}), {});
|
||||||
|
// Add members that are synthesized eagerly, such as subscripts.
|
||||||
|
for (auto member :
|
||||||
|
cast<NominalTypeDecl>(import)->getCurrentMembersWithoutLoading()) {
|
||||||
|
if (auto namedMember = dyn_cast<ValueDecl>(member)) {
|
||||||
|
if (namedMember->hasName() &&
|
||||||
|
namedMember->getName().getBaseName() == name &&
|
||||||
|
// Make sure we don't add duplicate entries, as that would
|
||||||
|
// wrongly imply that lookup is ambiguous.
|
||||||
|
!llvm::is_contained(baseResults, namedMember)) {
|
||||||
|
baseResults.push_back(namedMember);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for (auto foundInBase : baseResults) {
|
for (auto foundInBase : baseResults) {
|
||||||
if (auto newDecl = cloneBaseMemberDecl(foundInBase, recordDecl)) {
|
if (auto newDecl = clangModuleLoader->importBaseMemberDecl(
|
||||||
|
foundInBase, recordDecl)) {
|
||||||
result.push_back(newDecl);
|
result.push_back(newDecl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5761,6 +5778,18 @@ Decl *ClangImporter::importDeclDirectly(const clang::NamedDecl *decl) {
|
|||||||
return Impl.importDecl(decl, Impl.CurrentVersion);
|
return Impl.importDecl(decl, Impl.CurrentVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueDecl *ClangImporter::importBaseMemberDecl(ValueDecl *decl,
|
||||||
|
DeclContext *newContext) {
|
||||||
|
// Make sure we don't clone the decl again for this class, as that would
|
||||||
|
// result in multiple definitions of the same symbol.
|
||||||
|
std::pair<ValueDecl *, DeclContext *> key = {decl, newContext};
|
||||||
|
if (!Impl.clonedBaseMembers.count(key)) {
|
||||||
|
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext);
|
||||||
|
Impl.clonedBaseMembers[key] = cloned;
|
||||||
|
}
|
||||||
|
return Impl.clonedBaseMembers[key];
|
||||||
|
}
|
||||||
|
|
||||||
void ClangImporter::diagnoseTopLevelValue(const DeclName &name) {
|
void ClangImporter::diagnoseTopLevelValue(const DeclName &name) {
|
||||||
Impl.diagnoseTopLevelValue(name);
|
Impl.diagnoseTopLevelValue(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -621,6 +621,10 @@ public:
|
|||||||
llvm::DenseSet<clang::FunctionDecl *>>>>
|
llvm::DenseSet<clang::FunctionDecl *>>>>
|
||||||
cxxMethods;
|
cxxMethods;
|
||||||
|
|
||||||
|
// Keep track of the decls that were already cloned for this specific class.
|
||||||
|
llvm::DenseMap<std::pair<ValueDecl *, DeclContext *>, ValueDecl *>
|
||||||
|
clonedBaseMembers;
|
||||||
|
|
||||||
// Cache for already-specialized function templates and any thunks they may
|
// Cache for already-specialized function templates and any thunks they may
|
||||||
// have.
|
// have.
|
||||||
llvm::DenseMap<clang::FunctionDecl *, ValueDecl *>
|
llvm::DenseMap<clang::FunctionDecl *, ValueDecl *>
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %S/Inputs -enable-experimental-cxx-interop
|
||||||
|
|
||||||
|
import Functions
|
||||||
|
|
||||||
|
extension Base {
|
||||||
|
public func swiftFunc() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Derived().swiftFunc() // expected-error {{value of type 'Derived' has no member 'swiftFunc'}}
|
||||||
Reference in New Issue
Block a user