Skip to content

[cxx-interop] Lazily import members of clang namespaces and records via requests. #38675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions include/swift/ClangImporter/ClangImporterRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,164 @@
#include "swift/AST/SimpleRequest.h"
#include "swift/AST/ASTTypeIDs.h"
#include "swift/AST/EvaluatorDependencies.h"
#include "swift/AST/FileUnit.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/NameLookup.h"
#include "swift/Basic/Statistic.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/TinyPtrVector.h"

namespace swift {
class Decl;
class DeclName;
class EnumDecl;

/// The input type for a clang direct lookup request.
struct ClangDirectLookupDescriptor final {
Decl *decl;
const clang::Decl *clangDecl;
DeclName name;

ClangDirectLookupDescriptor(Decl *decl, const clang::Decl *clangDecl,
DeclName name)
: decl(decl), clangDecl(clangDecl), name(name) {}

friend llvm::hash_code hash_value(const ClangDirectLookupDescriptor &desc) {
return llvm::hash_combine(desc.name, desc.decl, desc.clangDecl);
}

friend bool operator==(const ClangDirectLookupDescriptor &lhs,
const ClangDirectLookupDescriptor &rhs) {
return lhs.name == rhs.name && lhs.decl == rhs.decl &&
lhs.clangDecl == rhs.clangDecl;
}

friend bool operator!=(const ClangDirectLookupDescriptor &lhs,
const ClangDirectLookupDescriptor &rhs) {
return !(lhs == rhs);
}
};

void simple_display(llvm::raw_ostream &out,
const ClangDirectLookupDescriptor &desc);
SourceLoc extractNearestSourceLoc(const ClangDirectLookupDescriptor &desc);

/// This matches SwiftLookupTable::SingleEntry;
using SingleEntry = llvm::PointerUnion<clang::NamedDecl *, clang::MacroInfo *,
clang::ModuleMacro *>;
/// Uses the appropriate SwiftLookupTable to find a set of clang decls given
/// their name.
class ClangDirectLookupRequest
: public SimpleRequest<ClangDirectLookupRequest,
SmallVector<SingleEntry, 4>(
ClangDirectLookupDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
SmallVector<SingleEntry, 4> evaluate(Evaluator &evaluator,
ClangDirectLookupDescriptor desc) const;
};

/// The input type for a namespace member lookup request.
struct CXXNamespaceMemberLookupDescriptor final {
EnumDecl *namespaceDecl;
DeclName name;

CXXNamespaceMemberLookupDescriptor(EnumDecl *namespaceDecl, DeclName name)
: namespaceDecl(namespaceDecl), name(name) {
assert(isa<clang::NamespaceDecl>(namespaceDecl->getClangDecl()));
}

friend llvm::hash_code
hash_value(const CXXNamespaceMemberLookupDescriptor &desc) {
return llvm::hash_combine(desc.name, desc.namespaceDecl);
}

friend bool operator==(const CXXNamespaceMemberLookupDescriptor &lhs,
const CXXNamespaceMemberLookupDescriptor &rhs) {
return lhs.name == rhs.name && lhs.namespaceDecl == rhs.namespaceDecl;
}

friend bool operator!=(const CXXNamespaceMemberLookupDescriptor &lhs,
const CXXNamespaceMemberLookupDescriptor &rhs) {
return !(lhs == rhs);
}
};

void simple_display(llvm::raw_ostream &out,
const CXXNamespaceMemberLookupDescriptor &desc);
SourceLoc
extractNearestSourceLoc(const CXXNamespaceMemberLookupDescriptor &desc);

/// Uses ClangDirectLookup to find a named member inside of the given namespace.
class CXXNamespaceMemberLookup
: public SimpleRequest<CXXNamespaceMemberLookup,
TinyPtrVector<ValueDecl *>(
CXXNamespaceMemberLookupDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
TinyPtrVector<ValueDecl *>
evaluate(Evaluator &evaluator, CXXNamespaceMemberLookupDescriptor desc) const;
};

/// The input type for a record member lookup request.
struct ClangRecordMemberLookupDescriptor final {
StructDecl *recordDecl;
DeclName name;

ClangRecordMemberLookupDescriptor(StructDecl *recordDecl, DeclName name)
: recordDecl(recordDecl), name(name) {
assert(isa<clang::RecordDecl>(recordDecl->getClangDecl()));
}

friend llvm::hash_code
hash_value(const ClangRecordMemberLookupDescriptor &desc) {
return llvm::hash_combine(desc.name, desc.recordDecl);
}

friend bool operator==(const ClangRecordMemberLookupDescriptor &lhs,
const ClangRecordMemberLookupDescriptor &rhs) {
return lhs.name == rhs.name && lhs.recordDecl == rhs.recordDecl;
}

friend bool operator!=(const ClangRecordMemberLookupDescriptor &lhs,
const ClangRecordMemberLookupDescriptor &rhs) {
return !(lhs == rhs);
}
};

void simple_display(llvm::raw_ostream &out,
const ClangRecordMemberLookupDescriptor &desc);
SourceLoc
extractNearestSourceLoc(const ClangRecordMemberLookupDescriptor &desc);

/// Uses ClangDirectLookup to find a named member inside of the given record.
class ClangRecordMemberLookup
: public SimpleRequest<ClangRecordMemberLookup,
TinyPtrVector<ValueDecl *>(
ClangRecordMemberLookupDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
TinyPtrVector<ValueDecl *>
evaluate(Evaluator &evaluator, ClangRecordMemberLookupDescriptor desc) const;
};

#define SWIFT_TYPEID_ZONE ClangImporter
#define SWIFT_TYPEID_HEADER "swift/ClangImporter/ClangImporterTypeIDZone.def"
Expand Down
9 changes: 9 additions & 0 deletions include/swift/ClangImporter/ClangImporterTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,12 @@
//
//===----------------------------------------------------------------------===//

SWIFT_REQUEST(ClangImporter, ClangDirectLookupRequest,
(SmallVector<SingleEntry, 4>(ClangDirectLookupDescriptor)), Uncached,
NoLocationInfo)
SWIFT_REQUEST(ClangImporter, CXXNamespaceMemberLookup,
Decl *(CXXNamespaceMemberLookupDescriptor), Uncached,
NoLocationInfo)
SWIFT_REQUEST(ClangImporter, ClangRecordMemberLookup,
Decl *(ClangRecordMemberLookupDescriptor), Uncached,
NoLocationInfo)
50 changes: 49 additions & 1 deletion lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "swift/AST/GenericSignature.h"
#include "swift/AST/Module.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PrintOptions.h"
#include "swift/AST/ProtocolConformance.h"
Expand All @@ -44,6 +45,7 @@
#include "swift/Basic/QuotedString.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/StringExtras.h"
#include "swift/ClangImporter/ClangImporterRequests.h"
#include "swift/Config.h"
#include "swift/Parse/Lexer.h"
#include "swift/Strings.h"
Expand Down Expand Up @@ -2157,10 +2159,54 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
indent();
}

// This provides logic for looking up all members of a namespace. This is
// intentionally implemented only in the printer and should *only* be used for
// debugging, testing, generating module dumps, etc. (In other words, if you're
// trying to get all the members of a namespace in another part of the compiler,
// you're probably doing somethign wrong. This is a very expensive operation,
// so we want to do it only when absolutely nessisary.)
static void addNamespaceMembers(Decl *decl,
llvm::SmallVector<Decl *, 16> &members) {
auto &ctx = decl->getASTContext();
auto namespaceDecl = cast<clang::NamespaceDecl>(decl->getClangDecl());

// This is only to keep track of the members we've already seen.
llvm::SmallPtrSet<Decl *, 16> addedMembers;
for (auto redecl : namespaceDecl->redecls()) {
for (auto member : redecl->decls()) {
if (auto classTemplate = dyn_cast<clang::ClassTemplateDecl>(member)) {
// Hack in the class template specializations that live here.
for (auto spec : classTemplate->specializations()) {
if (auto import =
ctx.getClangModuleLoader()->importDeclDirectly(spec))
if (addedMembers.insert(import).second)
members.push_back(import);
}
}

auto namedDecl = dyn_cast<clang::NamedDecl>(member);
if (!namedDecl)
continue;

auto name = ctx.getClangModuleLoader()->importName(namedDecl);
if (!name)
continue;

// If we're building libSyntaxParser, #if out the clang importer request
// because libSyntaxParser doesn't know about the clang importer.
CXXNamespaceMemberLookup lookupRequest({cast<EnumDecl>(decl), name});
for (auto found : evaluateOrDefault(ctx.evaluator, lookupRequest, {})) {
if (addedMembers.insert(found).second)
members.push_back(found);
}
}
}
}

void PrintAST::printMembersOfDecl(Decl *D, bool needComma,
bool openBracket,
bool closeBracket) {
llvm::SmallVector<Decl *, 3> Members;
llvm::SmallVector<Decl *, 16> Members;
auto AddMembers = [&](IterableDeclContext *idc) {
if (Options.PrintCurrentMembersOnly) {
for (auto RD : idc->getMembers())
Expand All @@ -2187,6 +2233,8 @@ void PrintAST::printMembersOfDecl(Decl *D, bool needComma,
}
}
}
if (isa_and_nonnull<clang::NamespaceDecl>(D->getClangDecl()))
addNamespaceMembers(D, Members);
}
printMembers(Members, needComma, openBracket, closeBracket);
}
Expand Down
35 changes: 28 additions & 7 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
#include "swift/ClangImporter/ClangImporterRequests.h"
#include "swift/Parse/Lexer.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/Debug.h"
Expand Down Expand Up @@ -1448,15 +1450,34 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,

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

Table.markLazilyComplete(baseName);
if (isa_and_nonnull<clang::NamespaceDecl>(decl->getClangDecl())) {
// Namespaces will never have any members so we can just return whatever
// the lookup finds.
return evaluateOrDefault(
ctx.evaluator, CXXNamespaceMemberLookup({cast<EnumDecl>(decl), name}),
{});
} else if (isa_and_nonnull<clang::RecordDecl>(decl->getClangDecl())) {
auto allFound = evaluateOrDefault(
ctx.evaluator,
ClangRecordMemberLookup({cast<StructDecl>(decl), name}), {});
// Add all the members we found, later we'll combine these with the
// existing members.
for (auto found : allFound)
Table.addMember(found);

populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl);
} else {
// The lookup table believes it doesn't have a complete accounting of this
// name - either because we're never seen it before, or another extension
// was registered since the last time we searched. Ask the loaders to give
// us a hand.
populateLookupTableEntryFromLazyIDCLoader(ctx, Table, baseName, decl);
populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl);
}

Table.markLazilyComplete(name.getBaseName());
}

// Look for a declaration with this name.
Expand Down
62 changes: 62 additions & 0 deletions lib/AST/NameLookupRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,68 @@ void UnqualifiedLookupRequest::writeDependencySink(
track.addTopLevelName(desc.Name.getBaseName());
}

// The following clang importer requests have some definitions here to prevent
// linker errors when building lib syntax parser (which doesn't link with the
// clang importer).

//----------------------------------------------------------------------------//
// ClangDirectLookupRequest computation.
//----------------------------------------------------------------------------//

void swift::simple_display(llvm::raw_ostream &out,
const ClangDirectLookupDescriptor &desc) {
out << "Looking up ";
simple_display(out, desc.name);
out << " in ";
simple_display(out, desc.decl);
}

SourceLoc
swift::extractNearestSourceLoc(const ClangDirectLookupDescriptor &desc) {
return extractNearestSourceLoc(desc.decl);
}

//----------------------------------------------------------------------------//
// CXXNamespaceMemberLookup computation.
//----------------------------------------------------------------------------//

void swift::simple_display(llvm::raw_ostream &out,
const CXXNamespaceMemberLookupDescriptor &desc) {
out << "Looking up ";
simple_display(out, desc.name);
out << " in ";
simple_display(out, desc.namespaceDecl);
}

SourceLoc
swift::extractNearestSourceLoc(const CXXNamespaceMemberLookupDescriptor &desc) {
return extractNearestSourceLoc(desc.namespaceDecl);
}

//----------------------------------------------------------------------------//
// ClangRecordMemberLookup computation.
//----------------------------------------------------------------------------//

void swift::simple_display(llvm::raw_ostream &out,
const ClangRecordMemberLookupDescriptor &desc) {
out << "Looking up ";
simple_display(out, desc.name);
out << " in ";
simple_display(out, desc.recordDecl);
}

SourceLoc
swift::extractNearestSourceLoc(const ClangRecordMemberLookupDescriptor &desc) {
return extractNearestSourceLoc(desc.recordDecl);
}

// Implement the clang importer type zone.
#define SWIFT_TYPEID_ZONE ClangImporter
#define SWIFT_TYPEID_HEADER "swift/ClangImporter/ClangImporterTypeIDZone.def"
#include "swift/Basic/ImplementTypeIDZone.h"
#undef SWIFT_TYPEID_ZONE
#undef SWIFT_TYPEID_HEADER

// Define request evaluation functions for each of the name lookup requests.
static AbstractRequestFunction *nameLookupRequestFunctions[] = {
#define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \
Expand Down
Loading