Skip to content

Commit 8621508

Browse files
authored
Merge pull request #71320 from beccadax/globally-lazy-maximum
[ClangImporter] Support lazy member loading for import-as-member globals in extensions
2 parents 18fcfcb + 3835a4b commit 8621508

File tree

4 files changed

+85
-68
lines changed

4 files changed

+85
-68
lines changed

lib/AST/NameLookup.cpp

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,10 @@ class swift::MemberLookupTable : public ASTAllocated<swift::MemberLookupTable> {
12771277
/// Add the given members to the lookup table.
12781278
void addMembers(DeclRange members);
12791279

1280+
/// Add the members of the extension to the lookup table, if necessary
1281+
/// registering it for future lazy member loading.
1282+
void addExtension(ExtensionDecl *ext);
1283+
12801284
void addExtensionWithLazyMembers(ExtensionDecl *ext) {
12811285
ExtensionsWithLazyMembers.push_back(ext);
12821286
}
@@ -1467,23 +1471,29 @@ void MemberLookupTable::addMembers(DeclRange members) {
14671471
}
14681472
}
14691473

1474+
void MemberLookupTable::addExtension(ExtensionDecl *ext) {
1475+
// If we can lazy-load this extension, only take the members we've loaded
1476+
// so far.
1477+
if (ext->hasLazyMembers()) {
1478+
addMembers(ext->getCurrentMembersWithoutLoading());
1479+
clearLazilyCompleteCache();
1480+
clearLazilyCompleteForMacroExpansionCache();
1481+
addExtensionWithLazyMembers(ext);
1482+
} else {
1483+
// Else, load all the members into the table.
1484+
addMembers(ext->getMembers());
1485+
}
1486+
addContainerWithMacroExpansions(ext);
1487+
}
1488+
14701489
void NominalTypeDecl::addedExtension(ExtensionDecl *ext) {
14711490
if (!LookupTable.getInt())
14721491
return;
14731492

14741493
auto *table = LookupTable.getPointer();
14751494
assert(table);
14761495

1477-
if (ext->wasDeserialized() || ext->hasClangNode()) {
1478-
table->addMembers(ext->getCurrentMembersWithoutLoading());
1479-
table->clearLazilyCompleteCache();
1480-
table->clearLazilyCompleteForMacroExpansionCache();
1481-
table->addExtensionWithLazyMembers(ext);
1482-
} else {
1483-
table->addMembers(ext->getMembers());
1484-
}
1485-
1486-
table->addContainerWithMacroExpansions(ext);
1496+
table->addExtension(ext);
14871497
}
14881498

14891499
void NominalTypeDecl::addedMember(Decl *member) {
@@ -1603,8 +1613,6 @@ populateLookupTableEntryFromExtensions(ASTContext &ctx,
16031613
continue;
16041614
}
16051615

1606-
assert(e->wasDeserialized() || e->hasClangNode() &&
1607-
"Extension without deserializable content has lazy members!");
16081616
assert(!e->hasUnparsedMembers());
16091617

16101618
populateLookupTableEntryFromLazyIDCLoader(ctx, table, name, e);
@@ -1965,21 +1973,7 @@ void NominalTypeDecl::prepareLookupTable() {
19651973

19661974
// Note: this calls prepareExtensions()
19671975
for (auto e : getExtensions()) {
1968-
// If we can lazy-load this extension, only take the members we've loaded
1969-
// so far.
1970-
//
1971-
// FIXME: This should be 'e->hasLazyMembers()' but that crashes` because
1972-
// some imported extensions don't have a Clang node, and only support
1973-
// LazyMemberLoader::loadAllMembers() and not
1974-
// LazyMemberLoader::loadNamedMembers().
1975-
if (e->wasDeserialized() || e->hasClangNode()) {
1976-
table->addMembers(e->getCurrentMembersWithoutLoading());
1977-
table->addExtensionWithLazyMembers(e);
1978-
continue;
1979-
}
1980-
1981-
// Else, load all the members into the table.
1982-
table->addMembers(e->getMembers());
1976+
table->addExtension(e);
19831977
}
19841978

19851979
// Any extensions added after this point will add their members to the

lib/ClangImporter/ClangImporter.cpp

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6226,13 +6226,11 @@ swift::extractNearestSourceLoc(const ClangCategoryLookupDescriptor &desc) {
62266226

62276227
TinyPtrVector<ValueDecl *>
62286228
ClangImporter::Implementation::loadNamedMembers(
6229-
const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) {
6230-
6229+
const IterableDeclContext *IDC, DeclBaseName N, uint64_t extra) {
62316230
auto *D = IDC->getDecl();
62326231
auto *DC = D->getInnermostDeclContext();
62336232
auto *CD = D->getClangDecl();
6234-
auto *CDC = cast<clang::DeclContext>(CD);
6235-
assert(CD && "loadNamedMembers on a Decl without a clangDecl");
6233+
auto *CDC = cast_or_null<clang::DeclContext>(CD);
62366234

62376235
auto *nominal = DC->getSelfNominalTypeDecl();
62386236
auto effectiveClangContext = getEffectiveClangContext(nominal);
@@ -6252,15 +6250,22 @@ ClangImporter::Implementation::loadNamedMembers(
62526250
// findLookupTable, below, handles the first two cases; we assert on the
62536251
// third.
62546252

6255-
auto CMO = getClangSubmoduleForDecl(CD);
6253+
llvm::Optional<clang::Module *> CMO;
6254+
if (CD)
6255+
CMO = getClangSubmoduleForDecl(CD);
6256+
else {
6257+
// IDC is an extension containing globals imported as members, so it doesn't
6258+
// have a clang node but the submodule pointer has been stashed in `extra`.
6259+
CMO = reinterpret_cast<clang::Module *>(static_cast<uintptr_t>(extra));
6260+
}
62566261
assert(CMO && "loadNamedMembers on a forward-declared Decl");
62576262

62586263
auto table = findLookupTable(*CMO);
62596264
assert(table && "clang module without lookup table");
62606265

6261-
assert(!isa<clang::NamespaceDecl>(CD) && "Namespace members should be loaded"
6262-
"via a request.");
6263-
assert(isa<clang::ObjCContainerDecl>(CD));
6266+
assert(!isa_and_nonnull<clang::NamespaceDecl>(CD)
6267+
&& "Namespace members should be loaded via a request.");
6268+
assert(!CD || isa<clang::ObjCContainerDecl>(CD));
62646269

62656270
// Force the members of the entire inheritance hierarchy to be loaded and
62666271
// deserialized before loading the named member of a class. This warms up
@@ -6275,32 +6280,37 @@ ClangImporter::Implementation::loadNamedMembers(
62756280

62766281
// TODO: update this to use the requestified lookup.
62776282
TinyPtrVector<ValueDecl *> Members;
6278-
for (auto entry : table->lookup(SerializedSwiftName(N),
6279-
effectiveClangContext)) {
6280-
if (!entry.is<clang::NamedDecl *>()) continue;
6281-
auto member = entry.get<clang::NamedDecl *>();
6282-
if (!isVisibleClangEntry(member)) continue;
62836283

6284-
// Skip Decls from different clang::DeclContexts
6285-
if (member->getDeclContext() != CDC) continue;
6286-
6287-
SmallVector<Decl*, 4> tmp;
6288-
insertMembersAndAlternates(member, tmp);
6289-
for (auto *TD : tmp) {
6290-
if (auto *V = dyn_cast<ValueDecl>(TD)) {
6291-
// Skip ValueDecls if they import under different names.
6292-
if (V->getBaseName() == N) {
6293-
Members.push_back(V);
6284+
// Lookup actual, factual clang-side members of the context. No need to do
6285+
// this if we're handling an import-as-member extension.
6286+
if (CD) {
6287+
for (auto entry : table->lookup(SerializedSwiftName(N),
6288+
effectiveClangContext)) {
6289+
if (!entry.is<clang::NamedDecl *>()) continue;
6290+
auto member = entry.get<clang::NamedDecl *>();
6291+
if (!isVisibleClangEntry(member)) continue;
6292+
6293+
// Skip Decls from different clang::DeclContexts
6294+
if (member->getDeclContext() != CDC) continue;
6295+
6296+
SmallVector<Decl*, 4> tmp;
6297+
insertMembersAndAlternates(member, tmp, DC);
6298+
for (auto *TD : tmp) {
6299+
if (auto *V = dyn_cast<ValueDecl>(TD)) {
6300+
// Skip ValueDecls if they import under different names.
6301+
if (V->getBaseName() == N) {
6302+
Members.push_back(V);
6303+
}
62946304
}
6295-
}
62966305

6297-
// If the property's accessors have alternate decls, we might have
6298-
// to import those too.
6299-
if (auto *ASD = dyn_cast<AbstractStorageDecl>(TD)) {
6300-
for (auto *AD : ASD->getAllAccessors()) {
6301-
for (auto *D : getAlternateDecls(AD)) {
6302-
if (D->getBaseName() == N)
6303-
Members.push_back(D);
6306+
// If the property's accessors have alternate decls, we might have
6307+
// to import those too.
6308+
if (auto *ASD = dyn_cast<AbstractStorageDecl>(TD)) {
6309+
for (auto *AD : ASD->getAllAccessors()) {
6310+
for (auto *D : getAlternateDecls(AD)) {
6311+
if (D->getBaseName() == N)
6312+
Members.push_back(D);
6313+
}
63046314
}
63056315
}
63066316
}
@@ -6313,11 +6323,14 @@ ClangImporter::Implementation::loadNamedMembers(
63136323
auto member = entry.get<clang::NamedDecl *>();
63146324
if (!isVisibleClangEntry(member)) continue;
63156325

6316-
// Skip Decls from different clang::DeclContexts
6317-
if (member->getDeclContext() != CDC) continue;
6326+
// Skip Decls from different clang::DeclContexts. We don't do this for
6327+
// import-as-member extensions because we don't know what decl context to
6328+
// expect; for instance, an enum constant is inside the enum decl, not in
6329+
// the translation unit.
6330+
if (CDC && member->getDeclContext() != CDC) continue;
63186331

63196332
SmallVector<Decl*, 4> tmp;
6320-
insertMembersAndAlternates(member, tmp);
6333+
insertMembersAndAlternates(member, tmp, DC);
63216334
for (auto *TD : tmp) {
63226335
if (auto *V = dyn_cast<ValueDecl>(TD)) {
63236336
// Skip ValueDecls if they import under different names.
@@ -6328,7 +6341,7 @@ ClangImporter::Implementation::loadNamedMembers(
63286341
}
63296342
}
63306343

6331-
if (N.isConstructor()) {
6344+
if (CD && N.isConstructor()) {
63326345
if (auto *classDecl = dyn_cast<ClassDecl>(D)) {
63336346
SmallVector<Decl *, 4> ctors;
63346347
importInheritedConstructors(cast<clang::ObjCInterfaceDecl>(CD),
@@ -6338,7 +6351,7 @@ ClangImporter::Implementation::loadNamedMembers(
63386351
}
63396352
}
63406353

6341-
if (!isa<ProtocolDecl>(D)) {
6354+
if (CD && !isa<ProtocolDecl>(D)) {
63426355
if (auto *OCD = dyn_cast<clang::ObjCContainerDecl>(CD)) {
63436356
SmallVector<Decl *, 1> newMembers;
63446357
importMirroredProtocolMembers(OCD, DC, N, newMembers);

lib/ClangImporter/ImportDecl.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9150,6 +9150,8 @@ void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
91509150
(isa<clang::FieldDecl>(nd) || nd == nd->getCanonicalDecl());
91519151
if (isCanonicalInContext && nd->getDeclContext() == clangRecord &&
91529152
isVisibleClangEntry(nd))
9153+
// We don't pass `swiftDecl` as `expectedDC` because we might be in a
9154+
// recursive call that adds base class members to a derived class.
91539155
insertMembersAndAlternates(nd, members);
91549156
}
91559157

@@ -9390,7 +9392,9 @@ void ClangImporter::Implementation::loadAllMembersOfObjcContainer(
93909392
}
93919393

93929394
void ClangImporter::Implementation::insertMembersAndAlternates(
9393-
const clang::NamedDecl *nd, SmallVectorImpl<Decl *> &members) {
9395+
const clang::NamedDecl *nd,
9396+
SmallVectorImpl<Decl *> &members,
9397+
DeclContext *expectedDC) {
93949398

93959399
size_t start = members.size();
93969400
llvm::SmallPtrSet<Decl *, 4> knownAlternateMembers;
@@ -9405,9 +9409,13 @@ void ClangImporter::Implementation::insertMembersAndAlternates(
94059409
return false;
94069410
}
94079411

9412+
// If no DC was provided, use wherever the primary decl was imported into.
9413+
if (!expectedDC)
9414+
expectedDC = member->getDeclContext();
9415+
94089416
// If there are alternate declarations for this member, add them.
94099417
for (auto alternate : getAlternateDecls(member)) {
9410-
if (alternate->getDeclContext() == member->getDeclContext() &&
9418+
if (alternate->getDeclContext() == expectedDC &&
94119419
knownAlternateMembers.insert(alternate).second) {
94129420
members.push_back(alternate);
94139421
}
@@ -9418,7 +9426,8 @@ void ClangImporter::Implementation::insertMembersAndAlternates(
94189426
if (shouldSuppressDeclImport(nd))
94199427
return true;
94209428

9421-
members.push_back(member);
9429+
if (member->getDeclContext() == expectedDC)
9430+
members.push_back(member);
94229431
if (nameVersion.supportsConcurrency()) {
94239432
assert(!asyncImport &&
94249433
"Should only have a single version with concurrency enabled");
@@ -9450,7 +9459,7 @@ void ClangImporter::Implementation::collectMembersToAdd(
94509459
if (nd && nd == nd->getCanonicalDecl() &&
94519460
nd->getDeclContext() == objcContainer &&
94529461
isVisibleClangEntry(nd))
9453-
insertMembersAndAlternates(nd, members);
9462+
insertMembersAndAlternates(nd, members, DC);
94549463
}
94559464

94569465
// Objective-C protocols don't require any special handling.

lib/ClangImporter/ImporterImpl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
16211621
Decl *D, DeclContext *DC,
16221622
SmallVectorImpl<Decl *> &members);
16231623
void insertMembersAndAlternates(const clang::NamedDecl *nd,
1624-
SmallVectorImpl<Decl *> &members);
1624+
SmallVectorImpl<Decl *> &members,
1625+
DeclContext *expectedDC = nullptr);
16251626
void loadAllMembersIntoExtension(Decl *D, uint64_t extra);
16261627

16271628
/// Imports \p decl under \p nameVersion with the name \p newName, and adds

0 commit comments

Comments
 (0)