Skip to content

Commit 401f334

Browse files
authored
Merge pull request #38675 from zoecarver/lazy-importer-namespaces
[cxx-interop] Lazily import members of clang namespaces and records via requests.
2 parents 8a3cae5 + b8e52a7 commit 401f334

27 files changed

+698
-383
lines changed

include/swift/ClangImporter/ClangImporterRequests.h

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,164 @@
1919
#include "swift/AST/SimpleRequest.h"
2020
#include "swift/AST/ASTTypeIDs.h"
2121
#include "swift/AST/EvaluatorDependencies.h"
22+
#include "swift/AST/FileUnit.h"
23+
#include "swift/AST/Identifier.h"
24+
#include "swift/AST/NameLookup.h"
25+
#include "swift/Basic/Statistic.h"
26+
#include "llvm/ADT/Hashing.h"
27+
#include "llvm/ADT/TinyPtrVector.h"
2228

2329
namespace swift {
30+
class Decl;
31+
class DeclName;
32+
class EnumDecl;
33+
34+
/// The input type for a clang direct lookup request.
35+
struct ClangDirectLookupDescriptor final {
36+
Decl *decl;
37+
const clang::Decl *clangDecl;
38+
DeclName name;
39+
40+
ClangDirectLookupDescriptor(Decl *decl, const clang::Decl *clangDecl,
41+
DeclName name)
42+
: decl(decl), clangDecl(clangDecl), name(name) {}
43+
44+
friend llvm::hash_code hash_value(const ClangDirectLookupDescriptor &desc) {
45+
return llvm::hash_combine(desc.name, desc.decl, desc.clangDecl);
46+
}
47+
48+
friend bool operator==(const ClangDirectLookupDescriptor &lhs,
49+
const ClangDirectLookupDescriptor &rhs) {
50+
return lhs.name == rhs.name && lhs.decl == rhs.decl &&
51+
lhs.clangDecl == rhs.clangDecl;
52+
}
53+
54+
friend bool operator!=(const ClangDirectLookupDescriptor &lhs,
55+
const ClangDirectLookupDescriptor &rhs) {
56+
return !(lhs == rhs);
57+
}
58+
};
59+
60+
void simple_display(llvm::raw_ostream &out,
61+
const ClangDirectLookupDescriptor &desc);
62+
SourceLoc extractNearestSourceLoc(const ClangDirectLookupDescriptor &desc);
63+
64+
/// This matches SwiftLookupTable::SingleEntry;
65+
using SingleEntry = llvm::PointerUnion<clang::NamedDecl *, clang::MacroInfo *,
66+
clang::ModuleMacro *>;
67+
/// Uses the appropriate SwiftLookupTable to find a set of clang decls given
68+
/// their name.
69+
class ClangDirectLookupRequest
70+
: public SimpleRequest<ClangDirectLookupRequest,
71+
SmallVector<SingleEntry, 4>(
72+
ClangDirectLookupDescriptor),
73+
RequestFlags::Uncached> {
74+
public:
75+
using SimpleRequest::SimpleRequest;
76+
77+
private:
78+
friend SimpleRequest;
79+
80+
// Evaluation.
81+
SmallVector<SingleEntry, 4> evaluate(Evaluator &evaluator,
82+
ClangDirectLookupDescriptor desc) const;
83+
};
84+
85+
/// The input type for a namespace member lookup request.
86+
struct CXXNamespaceMemberLookupDescriptor final {
87+
EnumDecl *namespaceDecl;
88+
DeclName name;
89+
90+
CXXNamespaceMemberLookupDescriptor(EnumDecl *namespaceDecl, DeclName name)
91+
: namespaceDecl(namespaceDecl), name(name) {
92+
assert(isa<clang::NamespaceDecl>(namespaceDecl->getClangDecl()));
93+
}
94+
95+
friend llvm::hash_code
96+
hash_value(const CXXNamespaceMemberLookupDescriptor &desc) {
97+
return llvm::hash_combine(desc.name, desc.namespaceDecl);
98+
}
99+
100+
friend bool operator==(const CXXNamespaceMemberLookupDescriptor &lhs,
101+
const CXXNamespaceMemberLookupDescriptor &rhs) {
102+
return lhs.name == rhs.name && lhs.namespaceDecl == rhs.namespaceDecl;
103+
}
104+
105+
friend bool operator!=(const CXXNamespaceMemberLookupDescriptor &lhs,
106+
const CXXNamespaceMemberLookupDescriptor &rhs) {
107+
return !(lhs == rhs);
108+
}
109+
};
110+
111+
void simple_display(llvm::raw_ostream &out,
112+
const CXXNamespaceMemberLookupDescriptor &desc);
113+
SourceLoc
114+
extractNearestSourceLoc(const CXXNamespaceMemberLookupDescriptor &desc);
115+
116+
/// Uses ClangDirectLookup to find a named member inside of the given namespace.
117+
class CXXNamespaceMemberLookup
118+
: public SimpleRequest<CXXNamespaceMemberLookup,
119+
TinyPtrVector<ValueDecl *>(
120+
CXXNamespaceMemberLookupDescriptor),
121+
RequestFlags::Uncached> {
122+
public:
123+
using SimpleRequest::SimpleRequest;
124+
125+
private:
126+
friend SimpleRequest;
127+
128+
// Evaluation.
129+
TinyPtrVector<ValueDecl *>
130+
evaluate(Evaluator &evaluator, CXXNamespaceMemberLookupDescriptor desc) const;
131+
};
132+
133+
/// The input type for a record member lookup request.
134+
struct ClangRecordMemberLookupDescriptor final {
135+
StructDecl *recordDecl;
136+
DeclName name;
137+
138+
ClangRecordMemberLookupDescriptor(StructDecl *recordDecl, DeclName name)
139+
: recordDecl(recordDecl), name(name) {
140+
assert(isa<clang::RecordDecl>(recordDecl->getClangDecl()));
141+
}
142+
143+
friend llvm::hash_code
144+
hash_value(const ClangRecordMemberLookupDescriptor &desc) {
145+
return llvm::hash_combine(desc.name, desc.recordDecl);
146+
}
147+
148+
friend bool operator==(const ClangRecordMemberLookupDescriptor &lhs,
149+
const ClangRecordMemberLookupDescriptor &rhs) {
150+
return lhs.name == rhs.name && lhs.recordDecl == rhs.recordDecl;
151+
}
152+
153+
friend bool operator!=(const ClangRecordMemberLookupDescriptor &lhs,
154+
const ClangRecordMemberLookupDescriptor &rhs) {
155+
return !(lhs == rhs);
156+
}
157+
};
158+
159+
void simple_display(llvm::raw_ostream &out,
160+
const ClangRecordMemberLookupDescriptor &desc);
161+
SourceLoc
162+
extractNearestSourceLoc(const ClangRecordMemberLookupDescriptor &desc);
163+
164+
/// Uses ClangDirectLookup to find a named member inside of the given record.
165+
class ClangRecordMemberLookup
166+
: public SimpleRequest<ClangRecordMemberLookup,
167+
TinyPtrVector<ValueDecl *>(
168+
ClangRecordMemberLookupDescriptor),
169+
RequestFlags::Uncached> {
170+
public:
171+
using SimpleRequest::SimpleRequest;
172+
173+
private:
174+
friend SimpleRequest;
175+
176+
// Evaluation.
177+
TinyPtrVector<ValueDecl *>
178+
evaluate(Evaluator &evaluator, ClangRecordMemberLookupDescriptor desc) const;
179+
};
24180

25181
#define SWIFT_TYPEID_ZONE ClangImporter
26182
#define SWIFT_TYPEID_HEADER "swift/ClangImporter/ClangImporterTypeIDZone.def"

include/swift/ClangImporter/ClangImporterTypeIDZone.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,12 @@
1515
//
1616
//===----------------------------------------------------------------------===//
1717

18+
SWIFT_REQUEST(ClangImporter, ClangDirectLookupRequest,
19+
(SmallVector<SingleEntry, 4>(ClangDirectLookupDescriptor)), Uncached,
20+
NoLocationInfo)
21+
SWIFT_REQUEST(ClangImporter, CXXNamespaceMemberLookup,
22+
Decl *(CXXNamespaceMemberLookupDescriptor), Uncached,
23+
NoLocationInfo)
24+
SWIFT_REQUEST(ClangImporter, ClangRecordMemberLookup,
25+
Decl *(ClangRecordMemberLookupDescriptor), Uncached,
26+
NoLocationInfo)

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"
@@ -2158,10 +2160,54 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
21582160
indent();
21592161
}
21602162

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

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/AST/NameLookupRequests.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,68 @@ void UnqualifiedLookupRequest::writeDependencySink(
412412
track.addTopLevelName(desc.Name.getBaseName());
413413
}
414414

415+
// The following clang importer requests have some definitions here to prevent
416+
// linker errors when building lib syntax parser (which doesn't link with the
417+
// clang importer).
418+
419+
//----------------------------------------------------------------------------//
420+
// ClangDirectLookupRequest computation.
421+
//----------------------------------------------------------------------------//
422+
423+
void swift::simple_display(llvm::raw_ostream &out,
424+
const ClangDirectLookupDescriptor &desc) {
425+
out << "Looking up ";
426+
simple_display(out, desc.name);
427+
out << " in ";
428+
simple_display(out, desc.decl);
429+
}
430+
431+
SourceLoc
432+
swift::extractNearestSourceLoc(const ClangDirectLookupDescriptor &desc) {
433+
return extractNearestSourceLoc(desc.decl);
434+
}
435+
436+
//----------------------------------------------------------------------------//
437+
// CXXNamespaceMemberLookup computation.
438+
//----------------------------------------------------------------------------//
439+
440+
void swift::simple_display(llvm::raw_ostream &out,
441+
const CXXNamespaceMemberLookupDescriptor &desc) {
442+
out << "Looking up ";
443+
simple_display(out, desc.name);
444+
out << " in ";
445+
simple_display(out, desc.namespaceDecl);
446+
}
447+
448+
SourceLoc
449+
swift::extractNearestSourceLoc(const CXXNamespaceMemberLookupDescriptor &desc) {
450+
return extractNearestSourceLoc(desc.namespaceDecl);
451+
}
452+
453+
//----------------------------------------------------------------------------//
454+
// ClangRecordMemberLookup computation.
455+
//----------------------------------------------------------------------------//
456+
457+
void swift::simple_display(llvm::raw_ostream &out,
458+
const ClangRecordMemberLookupDescriptor &desc) {
459+
out << "Looking up ";
460+
simple_display(out, desc.name);
461+
out << " in ";
462+
simple_display(out, desc.recordDecl);
463+
}
464+
465+
SourceLoc
466+
swift::extractNearestSourceLoc(const ClangRecordMemberLookupDescriptor &desc) {
467+
return extractNearestSourceLoc(desc.recordDecl);
468+
}
469+
470+
// Implement the clang importer type zone.
471+
#define SWIFT_TYPEID_ZONE ClangImporter
472+
#define SWIFT_TYPEID_HEADER "swift/ClangImporter/ClangImporterTypeIDZone.def"
473+
#include "swift/Basic/ImplementTypeIDZone.h"
474+
#undef SWIFT_TYPEID_ZONE
475+
#undef SWIFT_TYPEID_HEADER
476+
415477
// Define request evaluation functions for each of the name lookup requests.
416478
static AbstractRequestFunction *nameLookupRequestFunctions[] = {
417479
#define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \

0 commit comments

Comments
 (0)