mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-16 06:36:06 +00:00

We used to save out and eagerly load a (potentially huge) table of merged formerly-canonical declarations when we loaded each module. This was extremely inefficient in the presence of large amounts of merging, and didn't actually save any merging lookup work, because we still needed to perform name lookup to check that our merged declaration lists were complete. This also resulted in a loss of laziness -- even if we only needed an early declaration of an entity, we would eagerly pull in all declarations that had been merged into it regardless. We now store the relevant fragments of the table within the declarations themselves. In detail: * The first declaration of each entity within a module stores a list of first declarations from imported modules that are merged into it. * Loading that declaration pre-loads those other entities, so that they appear earlier within the redeclaration chain. * The name lookup tables list the most recent local lookup result, if there is one, or all directly-imported lookup results if not. llvm-svn: 231424
423 lines
13 KiB
C++
423 lines
13 KiB
C++
//===- IdentifierResolver.cpp - Lexical Scope Name lookup -------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the IdentifierResolver class, which is used for lexical
|
|
// scoped lookup, based on declaration names.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Sema/IdentifierResolver.h"
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/Basic/LangOptions.h"
|
|
#include "clang/Lex/ExternalPreprocessorSource.h"
|
|
#include "clang/Lex/Preprocessor.h"
|
|
#include "clang/Sema/Scope.h"
|
|
|
|
using namespace clang;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// IdDeclInfoMap class
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// IdDeclInfoMap - Associates IdDeclInfos with declaration names.
|
|
/// Allocates 'pools' (vectors of IdDeclInfos) to avoid allocating each
|
|
/// individual IdDeclInfo to heap.
|
|
class IdentifierResolver::IdDeclInfoMap {
|
|
static const unsigned int POOL_SIZE = 512;
|
|
|
|
/// We use our own linked-list implementation because it is sadly
|
|
/// impossible to add something to a pre-C++0x STL container without
|
|
/// a completely unnecessary copy.
|
|
struct IdDeclInfoPool {
|
|
IdDeclInfoPool(IdDeclInfoPool *Next) : Next(Next) {}
|
|
|
|
IdDeclInfoPool *Next;
|
|
IdDeclInfo Pool[POOL_SIZE];
|
|
};
|
|
|
|
IdDeclInfoPool *CurPool;
|
|
unsigned int CurIndex;
|
|
|
|
public:
|
|
IdDeclInfoMap() : CurPool(nullptr), CurIndex(POOL_SIZE) {}
|
|
|
|
~IdDeclInfoMap() {
|
|
IdDeclInfoPool *Cur = CurPool;
|
|
while (IdDeclInfoPool *P = Cur) {
|
|
Cur = Cur->Next;
|
|
delete P;
|
|
}
|
|
}
|
|
|
|
/// Returns the IdDeclInfo associated to the DeclarationName.
|
|
/// It creates a new IdDeclInfo if one was not created before for this id.
|
|
IdDeclInfo &operator[](DeclarationName Name);
|
|
};
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// IdDeclInfo Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// RemoveDecl - Remove the decl from the scope chain.
|
|
/// The decl must already be part of the decl chain.
|
|
void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) {
|
|
for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) {
|
|
if (D == *(I-1)) {
|
|
Decls.erase(I-1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
llvm_unreachable("Didn't find this decl on its identifier's chain!");
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// IdentifierResolver Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
IdentifierResolver::IdentifierResolver(Preprocessor &PP)
|
|
: LangOpt(PP.getLangOpts()), PP(PP),
|
|
IdDeclInfos(new IdDeclInfoMap) {
|
|
}
|
|
|
|
IdentifierResolver::~IdentifierResolver() {
|
|
delete IdDeclInfos;
|
|
}
|
|
|
|
/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
|
|
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
|
|
/// true if 'D' belongs to the given declaration context.
|
|
bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
|
|
bool AllowInlineNamespace) const {
|
|
Ctx = Ctx->getRedeclContext();
|
|
|
|
if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
|
|
// Ignore the scopes associated within transparent declaration contexts.
|
|
while (S->getEntity() && S->getEntity()->isTransparentContext())
|
|
S = S->getParent();
|
|
|
|
if (S->isDeclScope(D))
|
|
return true;
|
|
if (LangOpt.CPlusPlus) {
|
|
// C++ 3.3.2p3:
|
|
// The name declared in a catch exception-declaration is local to the
|
|
// handler and shall not be redeclared in the outermost block of the
|
|
// handler.
|
|
// C++ 3.3.2p4:
|
|
// Names declared in the for-init-statement, and in the condition of if,
|
|
// while, for, and switch statements are local to the if, while, for, or
|
|
// switch statement (including the controlled statement), and shall not be
|
|
// redeclared in a subsequent condition of that statement nor in the
|
|
// outermost block (or, for the if statement, any of the outermost blocks)
|
|
// of the controlled statement.
|
|
//
|
|
assert(S->getParent() && "No TUScope?");
|
|
if (S->getParent()->getFlags() & Scope::ControlScope) {
|
|
S = S->getParent();
|
|
if (S->isDeclScope(D))
|
|
return true;
|
|
}
|
|
if (S->getFlags() & Scope::FnTryCatchScope)
|
|
return S->getParent()->isDeclScope(D);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// FIXME: If D is a local extern declaration, this check doesn't make sense;
|
|
// we should be checking its lexical context instead in that case, because
|
|
// that is its scope.
|
|
DeclContext *DCtx = D->getDeclContext()->getRedeclContext();
|
|
return AllowInlineNamespace ? Ctx->InEnclosingNamespaceSetOf(DCtx)
|
|
: Ctx->Equals(DCtx);
|
|
}
|
|
|
|
/// AddDecl - Link the decl to its shadowed decl chain.
|
|
void IdentifierResolver::AddDecl(NamedDecl *D) {
|
|
DeclarationName Name = D->getDeclName();
|
|
if (IdentifierInfo *II = Name.getAsIdentifierInfo())
|
|
updatingIdentifier(*II);
|
|
|
|
void *Ptr = Name.getFETokenInfo<void>();
|
|
|
|
if (!Ptr) {
|
|
Name.setFETokenInfo(D);
|
|
return;
|
|
}
|
|
|
|
IdDeclInfo *IDI;
|
|
|
|
if (isDeclPtr(Ptr)) {
|
|
Name.setFETokenInfo(nullptr);
|
|
IDI = &(*IdDeclInfos)[Name];
|
|
NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
|
|
IDI->AddDecl(PrevD);
|
|
} else
|
|
IDI = toIdDeclInfo(Ptr);
|
|
|
|
IDI->AddDecl(D);
|
|
}
|
|
|
|
void IdentifierResolver::InsertDeclAfter(iterator Pos, NamedDecl *D) {
|
|
DeclarationName Name = D->getDeclName();
|
|
if (IdentifierInfo *II = Name.getAsIdentifierInfo())
|
|
updatingIdentifier(*II);
|
|
|
|
void *Ptr = Name.getFETokenInfo<void>();
|
|
|
|
if (!Ptr) {
|
|
AddDecl(D);
|
|
return;
|
|
}
|
|
|
|
if (isDeclPtr(Ptr)) {
|
|
// We only have a single declaration: insert before or after it,
|
|
// as appropriate.
|
|
if (Pos == iterator()) {
|
|
// Add the new declaration before the existing declaration.
|
|
NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
|
|
RemoveDecl(PrevD);
|
|
AddDecl(D);
|
|
AddDecl(PrevD);
|
|
} else {
|
|
// Add new declaration after the existing declaration.
|
|
AddDecl(D);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// General case: insert the declaration at the appropriate point in the
|
|
// list, which already has at least two elements.
|
|
IdDeclInfo *IDI = toIdDeclInfo(Ptr);
|
|
if (Pos.isIterator()) {
|
|
IDI->InsertDecl(Pos.getIterator() + 1, D);
|
|
} else
|
|
IDI->InsertDecl(IDI->decls_begin(), D);
|
|
}
|
|
|
|
/// RemoveDecl - Unlink the decl from its shadowed decl chain.
|
|
/// The decl must already be part of the decl chain.
|
|
void IdentifierResolver::RemoveDecl(NamedDecl *D) {
|
|
assert(D && "null param passed");
|
|
DeclarationName Name = D->getDeclName();
|
|
if (IdentifierInfo *II = Name.getAsIdentifierInfo())
|
|
updatingIdentifier(*II);
|
|
|
|
void *Ptr = Name.getFETokenInfo<void>();
|
|
|
|
assert(Ptr && "Didn't find this decl on its identifier's chain!");
|
|
|
|
if (isDeclPtr(Ptr)) {
|
|
assert(D == Ptr && "Didn't find this decl on its identifier's chain!");
|
|
Name.setFETokenInfo(nullptr);
|
|
return;
|
|
}
|
|
|
|
return toIdDeclInfo(Ptr)->RemoveDecl(D);
|
|
}
|
|
|
|
/// begin - Returns an iterator for decls with name 'Name'.
|
|
IdentifierResolver::iterator
|
|
IdentifierResolver::begin(DeclarationName Name) {
|
|
if (IdentifierInfo *II = Name.getAsIdentifierInfo())
|
|
readingIdentifier(*II);
|
|
|
|
void *Ptr = Name.getFETokenInfo<void>();
|
|
if (!Ptr) return end();
|
|
|
|
if (isDeclPtr(Ptr))
|
|
return iterator(static_cast<NamedDecl*>(Ptr));
|
|
|
|
IdDeclInfo *IDI = toIdDeclInfo(Ptr);
|
|
|
|
IdDeclInfo::DeclsTy::iterator I = IDI->decls_end();
|
|
if (I != IDI->decls_begin())
|
|
return iterator(I-1);
|
|
// No decls found.
|
|
return end();
|
|
}
|
|
|
|
namespace {
|
|
enum DeclMatchKind {
|
|
DMK_Different,
|
|
DMK_Replace,
|
|
DMK_Ignore
|
|
};
|
|
}
|
|
|
|
/// \brief Compare two declarations to see whether they are different or,
|
|
/// if they are the same, whether the new declaration should replace the
|
|
/// existing declaration.
|
|
static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) {
|
|
// If the declarations are identical, ignore the new one.
|
|
if (Existing == New)
|
|
return DMK_Ignore;
|
|
|
|
// If the declarations have different kinds, they're obviously different.
|
|
if (Existing->getKind() != New->getKind())
|
|
return DMK_Different;
|
|
|
|
// If the declarations are redeclarations of each other, keep the newest one.
|
|
if (Existing->getCanonicalDecl() == New->getCanonicalDecl()) {
|
|
// If we're adding an imported declaration, don't replace another imported
|
|
// declaration.
|
|
if (Existing->isFromASTFile() && New->isFromASTFile())
|
|
return DMK_Different;
|
|
|
|
// If either of these is the most recent declaration, use it.
|
|
Decl *MostRecent = Existing->getMostRecentDecl();
|
|
if (Existing == MostRecent)
|
|
return DMK_Ignore;
|
|
|
|
if (New == MostRecent)
|
|
return DMK_Replace;
|
|
|
|
// If the existing declaration is somewhere in the previous declaration
|
|
// chain of the new declaration, then prefer the new declaration.
|
|
for (auto RD : New->redecls()) {
|
|
if (RD == Existing)
|
|
return DMK_Replace;
|
|
|
|
if (RD->isCanonicalDecl())
|
|
break;
|
|
}
|
|
|
|
return DMK_Ignore;
|
|
}
|
|
|
|
return DMK_Different;
|
|
}
|
|
|
|
bool IdentifierResolver::tryAddTopLevelDecl(NamedDecl *D, DeclarationName Name){
|
|
if (IdentifierInfo *II = Name.getAsIdentifierInfo())
|
|
readingIdentifier(*II);
|
|
|
|
void *Ptr = Name.getFETokenInfo<void>();
|
|
|
|
if (!Ptr) {
|
|
Name.setFETokenInfo(D);
|
|
return true;
|
|
}
|
|
|
|
IdDeclInfo *IDI;
|
|
|
|
if (isDeclPtr(Ptr)) {
|
|
NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
|
|
|
|
switch (compareDeclarations(PrevD, D)) {
|
|
case DMK_Different:
|
|
break;
|
|
|
|
case DMK_Ignore:
|
|
return false;
|
|
|
|
case DMK_Replace:
|
|
Name.setFETokenInfo(D);
|
|
return true;
|
|
}
|
|
|
|
Name.setFETokenInfo(nullptr);
|
|
IDI = &(*IdDeclInfos)[Name];
|
|
|
|
// If the existing declaration is not visible in translation unit scope,
|
|
// then add the new top-level declaration first.
|
|
if (!PrevD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
|
|
IDI->AddDecl(D);
|
|
IDI->AddDecl(PrevD);
|
|
} else {
|
|
IDI->AddDecl(PrevD);
|
|
IDI->AddDecl(D);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
IDI = toIdDeclInfo(Ptr);
|
|
|
|
// See whether this declaration is identical to any existing declarations.
|
|
// If not, find the right place to insert it.
|
|
for (IdDeclInfo::DeclsTy::iterator I = IDI->decls_begin(),
|
|
IEnd = IDI->decls_end();
|
|
I != IEnd; ++I) {
|
|
|
|
switch (compareDeclarations(*I, D)) {
|
|
case DMK_Different:
|
|
break;
|
|
|
|
case DMK_Ignore:
|
|
return false;
|
|
|
|
case DMK_Replace:
|
|
*I = D;
|
|
return true;
|
|
}
|
|
|
|
if (!(*I)->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
|
|
// We've found a declaration that is not visible from the translation
|
|
// unit (it's in an inner scope). Insert our declaration here.
|
|
IDI->InsertDecl(I, D);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Add the declaration to the end.
|
|
IDI->AddDecl(D);
|
|
return true;
|
|
}
|
|
|
|
void IdentifierResolver::readingIdentifier(IdentifierInfo &II) {
|
|
if (II.isOutOfDate())
|
|
PP.getExternalSource()->updateOutOfDateIdentifier(II);
|
|
}
|
|
|
|
void IdentifierResolver::updatingIdentifier(IdentifierInfo &II) {
|
|
if (II.isOutOfDate())
|
|
PP.getExternalSource()->updateOutOfDateIdentifier(II);
|
|
|
|
if (II.isFromAST())
|
|
II.setChangedSinceDeserialization();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// IdDeclInfoMap Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Returns the IdDeclInfo associated to the DeclarationName.
|
|
/// It creates a new IdDeclInfo if one was not created before for this id.
|
|
IdentifierResolver::IdDeclInfo &
|
|
IdentifierResolver::IdDeclInfoMap::operator[](DeclarationName Name) {
|
|
void *Ptr = Name.getFETokenInfo<void>();
|
|
|
|
if (Ptr) return *toIdDeclInfo(Ptr);
|
|
|
|
if (CurIndex == POOL_SIZE) {
|
|
CurPool = new IdDeclInfoPool(CurPool);
|
|
CurIndex = 0;
|
|
}
|
|
IdDeclInfo *IDI = &CurPool->Pool[CurIndex];
|
|
Name.setFETokenInfo(reinterpret_cast<void*>(
|
|
reinterpret_cast<uintptr_t>(IDI) | 0x1)
|
|
);
|
|
++CurIndex;
|
|
return *IDI;
|
|
}
|
|
|
|
void IdentifierResolver::iterator::incrementSlowCase() {
|
|
NamedDecl *D = **this;
|
|
void *InfoPtr = D->getDeclName().getFETokenInfo<void>();
|
|
assert(!isDeclPtr(InfoPtr) && "Decl with wrong id ?");
|
|
IdDeclInfo *Info = toIdDeclInfo(InfoPtr);
|
|
|
|
BaseIter I = getIterator();
|
|
if (I != Info->decls_begin())
|
|
*this = iterator(I-1);
|
|
else // No more decls.
|
|
*this = iterator();
|
|
}
|