Skip to content

Commit b8e52a7

Browse files
committed
[cxx-interop] Lazily import members of Clang namespaces and records via requests.
Also adds a ClangImporter request zone and move some requests into it.
1 parent 0ca8dd3 commit b8e52a7

24 files changed

+391
-436
lines changed

include/swift/ClangImporter/ClangImporterRequests.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,21 @@ class EnumDecl;
3434
/// The input type for a clang direct lookup request.
3535
struct ClangDirectLookupDescriptor final {
3636
Decl *decl;
37+
const clang::Decl *clangDecl;
3738
DeclName name;
3839

39-
ClangDirectLookupDescriptor(Decl *decl, DeclName name)
40-
: decl(decl), name(name) {}
40+
ClangDirectLookupDescriptor(Decl *decl, const clang::Decl *clangDecl,
41+
DeclName name)
42+
: decl(decl), clangDecl(clangDecl), name(name) {}
4143

4244
friend llvm::hash_code hash_value(const ClangDirectLookupDescriptor &desc) {
43-
return llvm::hash_combine(desc.name, desc.decl);
45+
return llvm::hash_combine(desc.name, desc.decl, desc.clangDecl);
4446
}
4547

4648
friend bool operator==(const ClangDirectLookupDescriptor &lhs,
4749
const ClangDirectLookupDescriptor &rhs) {
48-
return lhs.name == rhs.name && lhs.decl == rhs.decl;
50+
return lhs.name == rhs.name && lhs.decl == rhs.decl &&
51+
lhs.clangDecl == rhs.clangDecl;
4952
}
5053

5154
friend bool operator!=(const ClangDirectLookupDescriptor &lhs,

lib/AST/ASTPrinter.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/AST/GenericSignature.h"
3131
#include "swift/AST/Module.h"
3232
#include "swift/AST/NameLookup.h"
33+
#include "swift/AST/NameLookupRequests.h"
3334
#include "swift/AST/ParameterList.h"
3435
#include "swift/AST/PrintOptions.h"
3536
#include "swift/AST/ProtocolConformance.h"
@@ -44,6 +45,7 @@
4445
#include "swift/Basic/QuotedString.h"
4546
#include "swift/Basic/STLExtras.h"
4647
#include "swift/Basic/StringExtras.h"
48+
#include "swift/ClangImporter/ClangImporterRequests.h"
4749
#include "swift/Config.h"
4850
#include "swift/Parse/Lexer.h"
4951
#include "swift/Strings.h"
@@ -2157,10 +2159,54 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
21572159
indent();
21582160
}
21592161

2162+
// This provides logic for looking up all members of a namespace. This is
2163+
// intentionally implemented only in the printer and should *only* be used for
2164+
// debugging, testing, generating module dumps, etc. (In other words, if you're
2165+
// trying to get all the members of a namespace in another part of the compiler,
2166+
// you're probably doing somethign wrong. This is a very expensive operation,
2167+
// so we want to do it only when absolutely nessisary.)
2168+
static void addNamespaceMembers(Decl *decl,
2169+
llvm::SmallVector<Decl *, 16> &members) {
2170+
auto &ctx = decl->getASTContext();
2171+
auto namespaceDecl = cast<clang::NamespaceDecl>(decl->getClangDecl());
2172+
2173+
// This is only to keep track of the members we've already seen.
2174+
llvm::SmallPtrSet<Decl *, 16> addedMembers;
2175+
for (auto redecl : namespaceDecl->redecls()) {
2176+
for (auto member : redecl->decls()) {
2177+
if (auto classTemplate = dyn_cast<clang::ClassTemplateDecl>(member)) {
2178+
// Hack in the class template specializations that live here.
2179+
for (auto spec : classTemplate->specializations()) {
2180+
if (auto import =
2181+
ctx.getClangModuleLoader()->importDeclDirectly(spec))
2182+
if (addedMembers.insert(import).second)
2183+
members.push_back(import);
2184+
}
2185+
}
2186+
2187+
auto namedDecl = dyn_cast<clang::NamedDecl>(member);
2188+
if (!namedDecl)
2189+
continue;
2190+
2191+
auto name = ctx.getClangModuleLoader()->importName(namedDecl);
2192+
if (!name)
2193+
continue;
2194+
2195+
// If we're building libSyntaxParser, #if out the clang importer request
2196+
// because libSyntaxParser doesn't know about the clang importer.
2197+
CXXNamespaceMemberLookup lookupRequest({cast<EnumDecl>(decl), name});
2198+
for (auto found : evaluateOrDefault(ctx.evaluator, lookupRequest, {})) {
2199+
if (addedMembers.insert(found).second)
2200+
members.push_back(found);
2201+
}
2202+
}
2203+
}
2204+
}
2205+
21602206
void PrintAST::printMembersOfDecl(Decl *D, bool needComma,
21612207
bool openBracket,
21622208
bool closeBracket) {
2163-
llvm::SmallVector<Decl *, 3> Members;
2209+
llvm::SmallVector<Decl *, 16> Members;
21642210
auto AddMembers = [&](IterableDeclContext *idc) {
21652211
if (Options.PrintCurrentMembersOnly) {
21662212
for (auto RD : idc->getMembers())
@@ -2187,6 +2233,8 @@ void PrintAST::printMembersOfDecl(Decl *D, bool needComma,
21872233
}
21882234
}
21892235
}
2236+
if (isa_and_nonnull<clang::NamespaceDecl>(D->getClangDecl()))
2237+
addNamespaceMembers(D, Members);
21902238
}
21912239
printMembers(Members, needComma, openBracket, closeBracket);
21922240
}

lib/AST/NameLookup.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
#include "swift/Basic/STLExtras.h"
3535
#include "swift/Basic/SourceManager.h"
3636
#include "swift/Basic/Statistic.h"
37+
#include "swift/ClangImporter/ClangImporterRequests.h"
3738
#include "swift/Parse/Lexer.h"
3839
#include "clang/AST/DeclObjC.h"
40+
#include "clang/Basic/Specifiers.h"
3941
#include "llvm/ADT/DenseMap.h"
4042
#include "llvm/ADT/TinyPtrVector.h"
4143
#include "llvm/Support/Debug.h"
@@ -1448,15 +1450,34 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
14481450

14491451
Table.updateLookupTable(decl);
14501452
} else if (!Table.isLazilyComplete(name.getBaseName())) {
1451-
// The lookup table believes it doesn't have a complete accounting of this
1452-
// name - either because we're never seen it before, or another extension
1453-
// was registered since the last time we searched. Ask the loaders to give
1454-
// us a hand.
14551453
DeclBaseName baseName(name.getBaseName());
1456-
populateLookupTableEntryFromLazyIDCLoader(ctx, Table, baseName, decl);
1457-
populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl);
14581454

1459-
Table.markLazilyComplete(baseName);
1455+
if (isa_and_nonnull<clang::NamespaceDecl>(decl->getClangDecl())) {
1456+
// Namespaces will never have any members so we can just return whatever
1457+
// the lookup finds.
1458+
return evaluateOrDefault(
1459+
ctx.evaluator, CXXNamespaceMemberLookup({cast<EnumDecl>(decl), name}),
1460+
{});
1461+
} else if (isa_and_nonnull<clang::RecordDecl>(decl->getClangDecl())) {
1462+
auto allFound = evaluateOrDefault(
1463+
ctx.evaluator,
1464+
ClangRecordMemberLookup({cast<StructDecl>(decl), name}), {});
1465+
// Add all the members we found, later we'll combine these with the
1466+
// existing members.
1467+
for (auto found : allFound)
1468+
Table.addMember(found);
1469+
1470+
populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl);
1471+
} else {
1472+
// The lookup table believes it doesn't have a complete accounting of this
1473+
// name - either because we're never seen it before, or another extension
1474+
// was registered since the last time we searched. Ask the loaders to give
1475+
// us a hand.
1476+
populateLookupTableEntryFromLazyIDCLoader(ctx, Table, baseName, decl);
1477+
populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl);
1478+
}
1479+
1480+
Table.markLazilyComplete(name.getBaseName());
14601481
}
14611482

14621483
// Look for a declaration with this name.

lib/ClangImporter/ClangImporter.cpp

Lines changed: 33 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@
6868
#include "llvm/Support/FileSystem.h"
6969
#include "llvm/Support/Memory.h"
7070
#include "llvm/Support/Path.h"
71-
#include "llvm/Support/YAMLTraits.h"
7271
#include "llvm/Support/YAMLParser.h"
72+
#include "llvm/Support/YAMLTraits.h"
7373
#include <algorithm>
7474
#include <memory>
7575

@@ -3863,11 +3863,6 @@ void ClangImporter::Implementation::lookupValue(
38633863
importDeclReal(clangDecl->getMostRecentDecl(), CurrentVersion,
38643864
/*useCanonicalDecl*/ !isNamespace);
38653865

3866-
if (isNamespace) {
3867-
if (auto extension = cast_or_null<ExtensionDecl>(realDecl))
3868-
realDecl = extension->getExtendedNominal();
3869-
}
3870-
38713866
if (!realDecl)
38723867
continue;
38733868
decl = cast<ValueDecl>(realDecl);
@@ -4049,7 +4044,7 @@ SmallVector<SwiftLookupTable::SingleEntry, 4>
40494044
ClangDirectLookupRequest::evaluate(Evaluator &evaluator,
40504045
ClangDirectLookupDescriptor desc) const {
40514046
auto &ctx = desc.decl->getASTContext();
4052-
auto *clangDecl = desc.decl->getClangDecl();
4047+
auto *clangDecl = desc.clangDecl;
40534048
// Class templates aren't in the lookup table.
40544049
if (auto spec = dyn_cast<clang::ClassTemplateSpecializationDecl>(clangDecl))
40554050
return lookupInClassTemplateSpecialization(ctx, spec, desc.name);
@@ -4065,49 +4060,20 @@ ClangDirectLookupRequest::evaluate(Evaluator &evaluator,
40654060

40664061
auto foundDecls = lookupTable->lookup(
40674062
SerializedSwiftName(desc.name.getBaseName()), effectiveClangContext);
4068-
// TODO: in `SwiftLookupTable::lookup` the `searchContext` is only a string.
4069-
// This is problematic because we might have two nested search contexts with
4070-
// the same name. The search context needs to be updated to be a decl (or
4071-
// decl context), but that will be a larger, seperate refactor. When that
4072-
// happens we can remove the below logic.
4073-
//
4074-
// We filter here by ensuring that each decl and all of its parents have the
4075-
// same name as `clangDecl` and its parents. This is prefered to checking the
4076-
// decl context pointer is equal to `clangDecl` because we may have a forward
4077-
// declared struct, multiple redecls of a namespace, or transparent contexts.
4078-
auto deepCompareDeclContexts = [](auto first, auto second) {
4079-
while (first->getParent() && second->getParent()) {
4080-
first = first->getParent();
4081-
second = second->getParent();
4082-
4083-
// Look through transparent contexts. If we have one (or more) extern C++
4084-
// contexts, that is the same as none.
4085-
while (first->isTransparentContext())
4086-
first = first->getParent();
4087-
while (second->isTransparentContext())
4088-
second = second->getParent();
4089-
4090-
auto firstName = dyn_cast<clang::NamedDecl>(first);
4091-
auto secondName = dyn_cast<clang::NamedDecl>(second);
4092-
4093-
if (!firstName || !secondName) {
4094-
if (firstName != secondName)
4095-
return false;
4096-
continue;
4097-
}
4098-
4099-
if (firstName->getName() != secondName->getName())
4100-
return false;
4101-
}
4102-
return !first->getParent() && !second->getParent();
4103-
};
4063+
// Make sure that `clangDecl` is the parent of all the members we found.
41044064
SmallVector<SwiftLookupTable::SingleEntry, 4> filteredDecls;
41054065
llvm::copy_if(
41064066
foundDecls, std::back_inserter(filteredDecls),
4107-
[&deepCompareDeclContexts, dc = cast<clang::DeclContext>(clangDecl)](
4108-
SwiftLookupTable::SingleEntry decl) {
4109-
return deepCompareDeclContexts(
4110-
decl.get<clang::NamedDecl *>()->getDeclContext(), dc);
4067+
[clangDecl](SwiftLookupTable::SingleEntry decl) {
4068+
auto first = decl.get<clang::NamedDecl *>()->getDeclContext();
4069+
auto second = cast<clang::DeclContext>(clangDecl);
4070+
if (auto firstDecl = dyn_cast<clang::Decl>(first)) {
4071+
if (auto secondDecl = dyn_cast<clang::Decl>(second))
4072+
return firstDecl->getCanonicalDecl() == secondDecl->getCanonicalDecl();
4073+
else
4074+
return false;
4075+
}
4076+
return first == second;
41114077
});
41124078
return filteredDecls;
41134079
}
@@ -4116,17 +4082,22 @@ TinyPtrVector<ValueDecl *> CXXNamespaceMemberLookup::evaluate(
41164082
Evaluator &evaluator, CXXNamespaceMemberLookupDescriptor desc) const {
41174083
EnumDecl *namespaceDecl = desc.namespaceDecl;
41184084
DeclName name = desc.name;
4119-
4085+
auto *clangNamespaceDecl =
4086+
cast<clang::NamespaceDecl>(namespaceDecl->getClangDecl());
41204087
auto &ctx = namespaceDecl->getASTContext();
4121-
auto allResults = evaluateOrDefault(
4122-
ctx.evaluator, ClangDirectLookupRequest({namespaceDecl, name}), {});
41234088

41244089
TinyPtrVector<ValueDecl *> result;
4125-
for (auto found : allResults) {
4126-
auto clangMember = found.get<clang::NamedDecl *>();
4127-
if (auto import =
4128-
ctx.getClangModuleLoader()->importDeclDirectly(clangMember))
4129-
result.push_back(cast<ValueDecl>(import));
4090+
for (auto redecl : clangNamespaceDecl->redecls()) {
4091+
auto allResults = evaluateOrDefault(
4092+
ctx.evaluator, ClangDirectLookupRequest({namespaceDecl, redecl, name}),
4093+
{});
4094+
4095+
for (auto found : allResults) {
4096+
auto clangMember = found.get<clang::NamedDecl *>();
4097+
if (auto import =
4098+
ctx.getClangModuleLoader()->importDeclDirectly(clangMember))
4099+
result.push_back(cast<ValueDecl>(import));
4100+
}
41304101
}
41314102

41324103
return result;
@@ -4139,7 +4110,9 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
41394110

41404111
auto &ctx = recordDecl->getASTContext();
41414112
auto allResults = evaluateOrDefault(
4142-
ctx.evaluator, ClangDirectLookupRequest({recordDecl, name}), {});
4113+
ctx.evaluator,
4114+
ClangDirectLookupRequest({recordDecl, recordDecl->getClangDecl(), name}),
4115+
{});
41434116

41444117
// Find the results that are actually a member of "recordDecl".
41454118
TinyPtrVector<ValueDecl *> result;
@@ -4188,8 +4161,9 @@ ClangImporter::Implementation::loadNamedMembers(
41884161
auto table = findLookupTable(*CMO);
41894162
assert(table && "clang module without lookup table");
41904163

4191-
assert(isa<clang::ObjCContainerDecl>(CD) || isa<clang::NamespaceDecl>(CD) ||
4192-
isa<clang::RecordDecl>(CD));
4164+
assert(!isa<clang::NamespaceDecl>(CD) && "Namespace members should be loaded"
4165+
"via a request.");
4166+
assert(isa<clang::ObjCContainerDecl>(CD));
41934167

41944168
// Force the members of the entire inheritance hierarchy to be loaded and
41954169
// deserialized before loading the named member of a class. This warms up
@@ -4202,6 +4176,7 @@ ClangImporter::Implementation::loadNamedMembers(
42024176
if (auto *superclassDecl = classDecl->getSuperclassDecl())
42034177
(void) const_cast<ClassDecl *>(superclassDecl)->lookupDirect(N);
42044178

4179+
// TODO: update this to use the requestified lookup.
42054180
TinyPtrVector<ValueDecl *> Members;
42064181
for (auto entry : table->lookup(SerializedSwiftName(N),
42074182
effectiveClangContext)) {

0 commit comments

Comments
 (0)