Skip to content

Commit 4245bd5

Browse files
authored
Merge pull request #60389 from apple/egorzhdan/cxx-record-lookup-ext
[cxx-interop] Clang member lookup should not look into Swift extensions
2 parents ce0794c + 51a1176 commit 4245bd5

File tree

5 files changed

+55
-5
lines changed

5 files changed

+55
-5
lines changed

include/swift/AST/ClangModuleLoader.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,11 @@ class ClangModuleLoader : public ModuleLoader {
184184
/// Imports a clang decl directly, rather than looking up its name.
185185
virtual Decl *importDeclDirectly(const clang::NamedDecl *decl) = 0;
186186

187+
/// Imports a clang decl from a base class, cloning it for \param newContext
188+
/// if it wasn't cloned for this specific context before.
189+
virtual ValueDecl *importBaseMemberDecl(ValueDecl *decl,
190+
DeclContext *newContext) = 0;
191+
187192
/// Emits diagnostics for any declarations named name
188193
/// whose direct declaration context is a TU.
189194
virtual void diagnoseTopLevelValue(const DeclName &name) = 0;

include/swift/ClangImporter/ClangImporter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,9 @@ class ClangImporter final : public ClangModuleLoader {
531531
/// Imports a clang decl directly, rather than looking up it's name.
532532
Decl *importDeclDirectly(const clang::NamedDecl *decl) override;
533533

534+
ValueDecl *importBaseMemberDecl(ValueDecl *decl,
535+
DeclContext *newContext) override;
536+
534537
/// Emits diagnostics for any declarations named name
535538
/// whose direct declaration context is a TU.
536539
void diagnoseTopLevelValue(const DeclName &name) override;

lib/ClangImporter/ClangImporter.cpp

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4935,11 +4935,12 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
49354935

49364936
// Find the results that are actually a member of "recordDecl".
49374937
TinyPtrVector<ValueDecl *> result;
4938+
ClangModuleLoader *clangModuleLoader = ctx.getClangModuleLoader();
49384939
for (auto found : allResults) {
49394940
auto named = found.get<clang::NamedDecl *>();
49404941
if (dyn_cast<clang::Decl>(named->getDeclContext()) ==
49414942
recordDecl->getClangDecl()) {
4942-
if (auto import = ctx.getClangModuleLoader()->importDeclDirectly(named))
4943+
if (auto import = clangModuleLoader->importDeclDirectly(named))
49434944
result.push_back(cast<ValueDecl>(import));
49444945
}
49454946
}
@@ -4955,16 +4956,32 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
49554956
continue;
49564957

49574958
auto *baseRecord = baseType->getAs<clang::RecordType>()->getDecl();
4958-
if (auto import =
4959-
ctx.getClangModuleLoader()->importDeclDirectly(baseRecord)) {
4959+
if (auto import = clangModuleLoader->importDeclDirectly(baseRecord)) {
49604960
// If we are looking up the base class, go no further. We will have
49614961
// already found it during the other lookup.
49624962
if (cast<ValueDecl>(import)->getName() == name)
49634963
continue;
49644964

4965-
auto baseResults = cast<NominalTypeDecl>(import)->lookupDirect(name);
4965+
// Add Clang members that are imported lazily.
4966+
auto baseResults = evaluateOrDefault(
4967+
ctx.evaluator,
4968+
ClangRecordMemberLookup({cast<NominalTypeDecl>(import), name}), {});
4969+
// Add members that are synthesized eagerly, such as subscripts.
4970+
for (auto member :
4971+
cast<NominalTypeDecl>(import)->getCurrentMembersWithoutLoading()) {
4972+
if (auto namedMember = dyn_cast<ValueDecl>(member)) {
4973+
if (namedMember->hasName() &&
4974+
namedMember->getName().getBaseName() == name &&
4975+
// Make sure we don't add duplicate entries, as that would
4976+
// wrongly imply that lookup is ambiguous.
4977+
!llvm::is_contained(baseResults, namedMember)) {
4978+
baseResults.push_back(namedMember);
4979+
}
4980+
}
4981+
}
49664982
for (auto foundInBase : baseResults) {
4967-
if (auto newDecl = cloneBaseMemberDecl(foundInBase, recordDecl)) {
4983+
if (auto newDecl = clangModuleLoader->importBaseMemberDecl(
4984+
foundInBase, recordDecl)) {
49684985
result.push_back(newDecl);
49694986
}
49704987
}
@@ -5761,6 +5778,18 @@ Decl *ClangImporter::importDeclDirectly(const clang::NamedDecl *decl) {
57615778
return Impl.importDecl(decl, Impl.CurrentVersion);
57625779
}
57635780

5781+
ValueDecl *ClangImporter::importBaseMemberDecl(ValueDecl *decl,
5782+
DeclContext *newContext) {
5783+
// Make sure we don't clone the decl again for this class, as that would
5784+
// result in multiple definitions of the same symbol.
5785+
std::pair<ValueDecl *, DeclContext *> key = {decl, newContext};
5786+
if (!Impl.clonedBaseMembers.count(key)) {
5787+
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext);
5788+
Impl.clonedBaseMembers[key] = cloned;
5789+
}
5790+
return Impl.clonedBaseMembers[key];
5791+
}
5792+
57645793
void ClangImporter::diagnoseTopLevelValue(const DeclName &name) {
57655794
Impl.diagnoseTopLevelValue(name);
57665795
}

lib/ClangImporter/ImporterImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,10 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
621621
llvm::DenseSet<clang::FunctionDecl *>>>>
622622
cxxMethods;
623623

624+
// Keep track of the decls that were already cloned for this specific class.
625+
llvm::DenseMap<std::pair<ValueDecl *, DeclContext *>, ValueDecl *>
626+
clonedBaseMembers;
627+
624628
// Cache for already-specialized function templates and any thunks they may
625629
// have.
626630
llvm::DenseMap<clang::FunctionDecl *, ValueDecl *>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %S/Inputs -enable-experimental-cxx-interop
2+
3+
import Functions
4+
5+
extension Base {
6+
public func swiftFunc() {}
7+
}
8+
9+
Derived().swiftFunc() // expected-error {{value of type 'Derived' has no member 'swiftFunc'}}

0 commit comments

Comments
 (0)