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.
|
||||
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
|
||||
/// whose direct declaration context is a TU.
|
||||
virtual void diagnoseTopLevelValue(const DeclName &name) = 0;
|
||||
|
||||
@@ -531,6 +531,9 @@ public:
|
||||
/// Imports a clang decl directly, rather than looking up it's name.
|
||||
Decl *importDeclDirectly(const clang::NamedDecl *decl) override;
|
||||
|
||||
ValueDecl *importBaseMemberDecl(ValueDecl *decl,
|
||||
DeclContext *newContext) override;
|
||||
|
||||
/// Emits diagnostics for any declarations named name
|
||||
/// whose direct declaration context is a TU.
|
||||
void diagnoseTopLevelValue(const DeclName &name) override;
|
||||
|
||||
@@ -4935,11 +4935,12 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
|
||||
|
||||
// Find the results that are actually a member of "recordDecl".
|
||||
TinyPtrVector<ValueDecl *> result;
|
||||
ClangModuleLoader *clangModuleLoader = ctx.getClangModuleLoader();
|
||||
for (auto found : allResults) {
|
||||
auto named = found.get<clang::NamedDecl *>();
|
||||
if (dyn_cast<clang::Decl>(named->getDeclContext()) ==
|
||||
recordDecl->getClangDecl()) {
|
||||
if (auto import = ctx.getClangModuleLoader()->importDeclDirectly(named))
|
||||
if (auto import = clangModuleLoader->importDeclDirectly(named))
|
||||
result.push_back(cast<ValueDecl>(import));
|
||||
}
|
||||
}
|
||||
@@ -4955,16 +4956,32 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
|
||||
continue;
|
||||
|
||||
auto *baseRecord = baseType->getAs<clang::RecordType>()->getDecl();
|
||||
if (auto import =
|
||||
ctx.getClangModuleLoader()->importDeclDirectly(baseRecord)) {
|
||||
if (auto import = clangModuleLoader->importDeclDirectly(baseRecord)) {
|
||||
// If we are looking up the base class, go no further. We will have
|
||||
// already found it during the other lookup.
|
||||
if (cast<ValueDecl>(import)->getName() == name)
|
||||
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) {
|
||||
if (auto newDecl = cloneBaseMemberDecl(foundInBase, recordDecl)) {
|
||||
if (auto newDecl = clangModuleLoader->importBaseMemberDecl(
|
||||
foundInBase, recordDecl)) {
|
||||
result.push_back(newDecl);
|
||||
}
|
||||
}
|
||||
@@ -5761,6 +5778,18 @@ Decl *ClangImporter::importDeclDirectly(const clang::NamedDecl *decl) {
|
||||
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) {
|
||||
Impl.diagnoseTopLevelValue(name);
|
||||
}
|
||||
|
||||
@@ -621,6 +621,10 @@ public:
|
||||
llvm::DenseSet<clang::FunctionDecl *>>>>
|
||||
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
|
||||
// have.
|
||||
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