Skip to content

Commit 3835a4b

Browse files
committed
[NFC] [ClangImporter] Fully support lazy loading
Previously, the lazily-created extensions used for globals imported as members of a type used the lazy module loader, but `ClangImporter::Implementation::loadNamedMembers()` didn’t actually work for them. Other parts of the compiler instead contrived to avoid loading these members by name by forcing all members to load before any selective loading might occur. This commit modifies that code path to accommodate extensions with no matching clang node, which is how these are represented. With this change, other parts of the compiler can unconditionally use the `LazyMemberLoader` whenever it is present. There may be performance improvements from this change, but I don’t expect any functional changes.
1 parent 6e44517 commit 3835a4b

File tree

2 files changed

+49
-43
lines changed

2 files changed

+49
-43
lines changed

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,12 +1474,7 @@ void MemberLookupTable::addMembers(DeclRange members) {
14741474
void MemberLookupTable::addExtension(ExtensionDecl *ext) {
14751475
// If we can lazy-load this extension, only take the members we've loaded
14761476
// so far.
1477-
//
1478-
// FIXME: This should be 'e->hasLazyMembers()' but that crashes` because
1479-
// some imported extensions don't have a Clang node, and only support
1480-
// LazyMemberLoader::loadAllMembers() and not
1481-
// LazyMemberLoader::loadNamedMembers().
1482-
if (ext->wasDeserialized() || ext->hasClangNode()) {
1477+
if (ext->hasLazyMembers()) {
14831478
addMembers(ext->getCurrentMembersWithoutLoading());
14841479
clearLazilyCompleteCache();
14851480
clearLazilyCompleteForMacroExpansionCache();
@@ -1618,8 +1613,6 @@ populateLookupTableEntryFromExtensions(ASTContext &ctx,
16181613
continue;
16191614
}
16201615

1621-
assert(e->wasDeserialized() || e->hasClangNode() &&
1622-
"Extension without deserializable content has lazy members!");
16231616
assert(!e->hasUnparsedMembers());
16241617

16251618
populateLookupTableEntryFromLazyIDCLoader(ctx, table, name, e);

lib/ClangImporter/ClangImporter.cpp

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6222,13 +6222,11 @@ swift::extractNearestSourceLoc(const ClangCategoryLookupDescriptor &desc) {
62226222

62236223
TinyPtrVector<ValueDecl *>
62246224
ClangImporter::Implementation::loadNamedMembers(
6225-
const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) {
6226-
6225+
const IterableDeclContext *IDC, DeclBaseName N, uint64_t extra) {
62276226
auto *D = IDC->getDecl();
62286227
auto *DC = D->getInnermostDeclContext();
62296228
auto *CD = D->getClangDecl();
6230-
auto *CDC = cast<clang::DeclContext>(CD);
6231-
assert(CD && "loadNamedMembers on a Decl without a clangDecl");
6229+
auto *CDC = cast_or_null<clang::DeclContext>(CD);
62326230

62336231
auto *nominal = DC->getSelfNominalTypeDecl();
62346232
auto effectiveClangContext = getEffectiveClangContext(nominal);
@@ -6248,15 +6246,22 @@ ClangImporter::Implementation::loadNamedMembers(
62486246
// findLookupTable, below, handles the first two cases; we assert on the
62496247
// third.
62506248

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

62546259
auto table = findLookupTable(*CMO);
62556260
assert(table && "clang module without lookup table");
62566261

6257-
assert(!isa<clang::NamespaceDecl>(CD) && "Namespace members should be loaded"
6258-
"via a request.");
6259-
assert(isa<clang::ObjCContainerDecl>(CD));
6262+
assert(!isa_and_nonnull<clang::NamespaceDecl>(CD)
6263+
&& "Namespace members should be loaded via a request.");
6264+
assert(!CD || isa<clang::ObjCContainerDecl>(CD));
62606265

62616266
// Force the members of the entire inheritance hierarchy to be loaded and
62626267
// deserialized before loading the named member of a class. This warms up
@@ -6271,32 +6276,37 @@ ClangImporter::Implementation::loadNamedMembers(
62716276

62726277
// TODO: update this to use the requestified lookup.
62736278
TinyPtrVector<ValueDecl *> Members;
6274-
for (auto entry : table->lookup(SerializedSwiftName(N),
6275-
effectiveClangContext)) {
6276-
if (!entry.is<clang::NamedDecl *>()) continue;
6277-
auto member = entry.get<clang::NamedDecl *>();
6278-
if (!isVisibleClangEntry(member)) continue;
6279-
6280-
// Skip Decls from different clang::DeclContexts
6281-
if (member->getDeclContext() != CDC) continue;
62826279

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

6293-
// If the property's accessors have alternate decls, we might have
6294-
// to import those too.
6295-
if (auto *ASD = dyn_cast<AbstractStorageDecl>(TD)) {
6296-
for (auto *AD : ASD->getAllAccessors()) {
6297-
for (auto *D : getAlternateDecls(AD)) {
6298-
if (D->getBaseName() == N)
6299-
Members.push_back(D);
6302+
// If the property's accessors have alternate decls, we might have
6303+
// to import those too.
6304+
if (auto *ASD = dyn_cast<AbstractStorageDecl>(TD)) {
6305+
for (auto *AD : ASD->getAllAccessors()) {
6306+
for (auto *D : getAlternateDecls(AD)) {
6307+
if (D->getBaseName() == N)
6308+
Members.push_back(D);
6309+
}
63006310
}
63016311
}
63026312
}
@@ -6309,8 +6319,11 @@ ClangImporter::Implementation::loadNamedMembers(
63096319
auto member = entry.get<clang::NamedDecl *>();
63106320
if (!isVisibleClangEntry(member)) continue;
63116321

6312-
// Skip Decls from different clang::DeclContexts
6313-
if (member->getDeclContext() != CDC) continue;
6322+
// Skip Decls from different clang::DeclContexts. We don't do this for
6323+
// import-as-member extensions because we don't know what decl context to
6324+
// expect; for instance, an enum constant is inside the enum decl, not in
6325+
// the translation unit.
6326+
if (CDC && member->getDeclContext() != CDC) continue;
63146327

63156328
SmallVector<Decl*, 4> tmp;
63166329
insertMembersAndAlternates(member, tmp, DC);
@@ -6324,7 +6337,7 @@ ClangImporter::Implementation::loadNamedMembers(
63246337
}
63256338
}
63266339

6327-
if (N.isConstructor()) {
6340+
if (CD && N.isConstructor()) {
63286341
if (auto *classDecl = dyn_cast<ClassDecl>(D)) {
63296342
SmallVector<Decl *, 4> ctors;
63306343
importInheritedConstructors(cast<clang::ObjCInterfaceDecl>(CD),
@@ -6334,7 +6347,7 @@ ClangImporter::Implementation::loadNamedMembers(
63346347
}
63356348
}
63366349

6337-
if (!isa<ProtocolDecl>(D)) {
6350+
if (CD && !isa<ProtocolDecl>(D)) {
63386351
if (auto *OCD = dyn_cast<clang::ObjCContainerDecl>(CD)) {
63396352
SmallVector<Decl *, 1> newMembers;
63406353
importMirroredProtocolMembers(OCD, DC, N, newMembers);

0 commit comments

Comments
 (0)