Skip to content

Commit 43d360c

Browse files
committed
[Clang importer] Eliminate redundant imports of C++ fields as properties
A recent refactoring uncovered two places where we could end up importing a C++ field declaration as a property more than once: 1. Importing the declaration context of a field in C++ mode can then go import all of the fields. In such a case, check that the field we're importing didn't happen already, and bail out early if it did. This is common practice in the Clang importer but wasn't happening here. 2. One caller to the function that imported a field from a C++ base class into its inheriting class (as a computed property) wasn't checking the cache, and therefore created a redundant version. Fix both issues.
1 parent 234534e commit 43d360c

File tree

3 files changed

+25
-9
lines changed

3 files changed

+25
-9
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5006,7 +5006,8 @@ DeclAttributes cloneImportedAttributes(ValueDecl *decl, ASTContext &context) {
50065006
return attrs;
50075007
}
50085008

5009-
ValueDecl *cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
5009+
static ValueDecl *
5010+
cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
50105011
if (auto fn = dyn_cast<FuncDecl>(decl)) {
50115012
// TODO: function templates are specialized during type checking so to
50125013
// support these we need to tell Swift to type check the synthesized bodies.
@@ -6290,16 +6291,23 @@ Decl *ClangImporter::importDeclDirectly(const clang::NamedDecl *decl) {
62906291
return Impl.importDecl(decl, Impl.CurrentVersion);
62916292
}
62926293

6293-
ValueDecl *ClangImporter::importBaseMemberDecl(ValueDecl *decl,
6294-
DeclContext *newContext) {
6294+
ValueDecl *ClangImporter::Implementation::importBaseMemberDecl(
6295+
ValueDecl *decl, DeclContext *newContext) {
62956296
// Make sure we don't clone the decl again for this class, as that would
62966297
// result in multiple definitions of the same symbol.
62976298
std::pair<ValueDecl *, DeclContext *> key = {decl, newContext};
6298-
if (!Impl.clonedBaseMembers.count(key)) {
6299+
auto known = clonedBaseMembers.find(key);
6300+
if (known == clonedBaseMembers.end()) {
62996301
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext);
6300-
Impl.clonedBaseMembers[key] = cloned;
6302+
known = clonedBaseMembers.insert({key, cloned}).first;
63016303
}
6302-
return Impl.clonedBaseMembers[key];
6304+
6305+
return known->second;
6306+
}
6307+
6308+
ValueDecl *ClangImporter::importBaseMemberDecl(ValueDecl *decl,
6309+
DeclContext *newContext) {
6310+
return Impl.importBaseMemberDecl(decl, newContext);
63036311
}
63046312

63056313
void ClangImporter::diagnoseTopLevelValue(const DeclName &name) {

lib/ClangImporter/ImportDecl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,6 +3581,12 @@ namespace {
35813581
if (!dc)
35823582
return nullptr;
35833583

3584+
// While importing the DeclContext, we might have imported the decl
3585+
// itself.
3586+
auto known = Impl.importDeclCached(decl, getVersion());
3587+
if (known.has_value())
3588+
return known.value();
3589+
35843590
// TODO: do we want to emit a diagnostic here?
35853591
// Types that are marked as foreign references cannot be stored by value.
35863592
if (auto recordType =
@@ -8761,8 +8767,6 @@ static void loadAllMembersOfSuperclassIfNeeded(ClassDecl *CD) {
87618767
E->loadAllMembers();
87628768
}
87638769

8764-
ValueDecl *cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext);
8765-
87668770
void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
87678771
NominalTypeDecl *swiftDecl, const clang::RecordDecl *clangRecord) {
87688772
// Import all of the members.
@@ -8793,7 +8797,7 @@ void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
87938797
// This means we found a member in a C++ record's base class.
87948798
if (swiftDecl->getClangDecl() != clangRecord) {
87958799
// So we need to clone the member into the derived class.
8796-
if (auto newDecl = cloneBaseMemberDecl(cast<ValueDecl>(member), swiftDecl)) {
8800+
if (auto newDecl = importBaseMemberDecl(cast<ValueDecl>(member), swiftDecl)) {
87978801
swiftDecl->addMember(newDecl);
87988802
}
87998803
continue;

lib/ClangImporter/ImporterImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,10 +642,14 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
642642
llvm::MapVector<std::pair<NominalTypeDecl *, Type>,
643643
std::pair<FuncDecl *, FuncDecl *>> cxxSubscripts;
644644

645+
private:
645646
// Keep track of the decls that were already cloned for this specific class.
646647
llvm::DenseMap<std::pair<ValueDecl *, DeclContext *>, ValueDecl *>
647648
clonedBaseMembers;
648649

650+
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext);
651+
652+
public:
649653
// Cache for already-specialized function templates and any thunks they may
650654
// have.
651655
llvm::DenseMap<clang::FunctionDecl *, ValueDecl *>

0 commit comments

Comments
 (0)