summaryrefslogtreecommitdiffstats
path: root/clang/lib/Serialization/ASTReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Serialization/ASTReader.cpp')
-rw-r--r--clang/lib/Serialization/ASTReader.cpp257
1 files changed, 181 insertions, 76 deletions
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index f4044624d07..b41bfa1255e 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -20,7 +20,6 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Frontend/PCHContainerOperations.h"
-#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
@@ -904,13 +903,6 @@ unsigned DeclarationNameKey::getHash() const {
return ID.ComputeHash();
}
-ModuleFile *
-ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) {
- using namespace llvm::support;
- uint32_t ModuleFileID = endian::readNext<uint32_t, little, unaligned>(d);
- return Reader.getLocalModuleFile(F, ModuleFileID);
-}
-
std::pair<unsigned, unsigned>
ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char *&d) {
using namespace llvm::support;
@@ -956,15 +948,15 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) {
return DeclarationNameKey(Kind, Data);
}
-void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type,
- const unsigned char *d,
- unsigned DataLen,
- data_type_builder &Val) {
+ASTDeclContextNameLookupTrait::data_type
+ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
+ const unsigned char *d,
+ unsigned DataLen) {
using namespace llvm::support;
- for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) {
- uint32_t LocalID = endian::readNext<uint32_t, little, unaligned>(d);
- Val.insert(Reader.getGlobalDeclID(F, LocalID));
- }
+ unsigned NumDecls = DataLen / 4;
+ LE32DeclID *Start = reinterpret_cast<LE32DeclID *>(
+ const_cast<unsigned char *>(d));
+ return std::make_pair(Start, Start + NumDecls);
}
bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M,
@@ -1023,8 +1015,9 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M,
// We can't safely determine the primary context yet, so delay attaching the
// lookup table until we're done with recursive deserialization.
- auto *Data = (const unsigned char*)Blob.data();
- PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data});
+ unsigned BucketOffset = Record[0];
+ PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{
+ &M, (const unsigned char *)Blob.data(), BucketOffset});
return false;
}
@@ -2559,7 +2552,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
unsigned Idx = 0;
serialization::DeclID ID = ReadDeclID(F, Record, Idx);
auto *Data = (const unsigned char*)Blob.data();
- PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data});
+ unsigned BucketOffset = Record[Idx++];
+ PendingVisibleUpdates[ID].push_back(
+ PendingVisibleUpdate{&F, Data, BucketOffset});
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
@@ -6360,48 +6355,196 @@ void ASTReader::FindFileRegionDecls(FileID File,
Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt)));
}
+/// \brief Retrieve the "definitive" module file for the definition of the
+/// given declaration context, if there is one.
+///
+/// The "definitive" module file is the only place where we need to look to
+/// find information about the declarations within the given declaration
+/// context. For example, C++ and Objective-C classes, C structs/unions, and
+/// Objective-C protocols, categories, and extensions are all defined in a
+/// single place in the source code, so they have definitive module files
+/// associated with them. C++ namespaces, on the other hand, can have
+/// definitions in multiple different module files.
+///
+/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's
+/// NDEBUG checking.
+static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC,
+ ASTReader &Reader) {
+ if (const DeclContext *DefDC = getDefinitiveDeclContext(DC))
+ return Reader.getOwningModuleFile(cast<Decl>(DefDC));
+
+ return nullptr;
+}
+
+namespace {
+ /// \brief ModuleFile visitor used to perform name lookup into a
+ /// declaration context.
+ class DeclContextNameLookupVisitor {
+ ASTReader &Reader;
+ const DeclContext *Context;
+ DeclarationName Name;
+ DeclarationNameKey NameKey;
+ unsigned NameHash;
+ SmallVectorImpl<NamedDecl *> &Decls;
+ llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet;
+
+ public:
+ DeclContextNameLookupVisitor(ASTReader &Reader, const DeclContext *Context,
+ DeclarationName Name,
+ SmallVectorImpl<NamedDecl *> &Decls,
+ llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet)
+ : Reader(Reader), Context(Context), Name(Name), NameKey(Name),
+ NameHash(NameKey.getHash()), Decls(Decls), DeclSet(DeclSet) {}
+
+ bool operator()(ModuleFile &M) {
+ // Check whether we have any visible declaration information for
+ // this context in this module.
+ auto Info = M.DeclContextInfos.find(Context);
+ if (Info == M.DeclContextInfos.end() || !Info->second.NameLookupTableData)
+ return false;
+
+ // Look for this name within this module.
+ ASTDeclContextNameLookupTable *LookupTable =
+ Info->second.NameLookupTableData;
+ ASTDeclContextNameLookupTable::iterator Pos =
+ LookupTable->find_hashed(NameKey, NameHash);
+ if (Pos == LookupTable->end())
+ return false;
+
+ bool FoundAnything = false;
+ ASTDeclContextNameLookupTrait::data_type Data = *Pos;
+ for (; Data.first != Data.second; ++Data.first) {
+ NamedDecl *ND = Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
+ if (!ND)
+ continue;
+
+ if (ND->getDeclName() != Name) {
+ // Not all names map to a unique DeclarationNameKey.
+ assert(DeclarationNameKey(ND->getDeclName()) == NameKey &&
+ "mismatched name for decl in decl context lookup table?");
+ continue;
+ }
+
+ // Record this declaration.
+ FoundAnything = true;
+ if (DeclSet.insert(ND).second)
+ Decls.push_back(ND);
+ }
+
+ return FoundAnything;
+ }
+ };
+}
+
bool
ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
- assert(DC->hasExternalVisibleStorage() && DC == DC->getPrimaryContext() &&
+ assert(DC->hasExternalVisibleStorage() &&
"DeclContext has no visible decls in storage");
if (!Name)
return false;
- auto It = Lookups.find(DC);
- if (It == Lookups.end())
- return false;
-
Deserializing LookupResults(this);
- // Load the list of declarations.
SmallVector<NamedDecl *, 64> Decls;
- for (DeclID ID : It->second.Table.find(Name)) {
- NamedDecl *ND = cast<NamedDecl>(GetDecl(ID));
- if (ND->getDeclName() == Name)
- Decls.push_back(ND);
- }
+ llvm::SmallPtrSet<NamedDecl*, 64> DeclSet;
+
+ DeclContextNameLookupVisitor Visitor(*this, DC, Name, Decls, DeclSet);
+
+ // If we can definitively determine which module file to look into,
+ // only look there. Otherwise, look in all module files.
+ if (ModuleFile *Definitive = getDefinitiveModuleFileFor(DC, *this))
+ Visitor(*Definitive);
+ else
+ ModuleMgr.visit(Visitor);
++NumVisibleDeclContextsRead;
SetExternalVisibleDeclsForName(DC, Name, Decls);
return !Decls.empty();
}
+namespace {
+ /// \brief ModuleFile visitor used to retrieve all visible names in a
+ /// declaration context.
+ class DeclContextAllNamesVisitor {
+ ASTReader &Reader;
+ SmallVectorImpl<const DeclContext *> &Contexts;
+ DeclsMap &Decls;
+ llvm::SmallPtrSet<NamedDecl *, 256> DeclSet;
+ bool VisitAll;
+
+ public:
+ DeclContextAllNamesVisitor(ASTReader &Reader,
+ SmallVectorImpl<const DeclContext *> &Contexts,
+ DeclsMap &Decls, bool VisitAll)
+ : Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { }
+
+ bool operator()(ModuleFile &M) {
+ // Check whether we have any visible declaration information for
+ // this context in this module.
+ ModuleFile::DeclContextInfosMap::iterator Info;
+ bool FoundInfo = false;
+ for (unsigned I = 0, N = Contexts.size(); I != N; ++I) {
+ Info = M.DeclContextInfos.find(Contexts[I]);
+ if (Info != M.DeclContextInfos.end() &&
+ Info->second.NameLookupTableData) {
+ FoundInfo = true;
+ break;
+ }
+ }
+
+ if (!FoundInfo)
+ return false;
+
+ ASTDeclContextNameLookupTable *LookupTable =
+ Info->second.NameLookupTableData;
+ bool FoundAnything = false;
+ for (ASTDeclContextNameLookupTable::data_iterator
+ I = LookupTable->data_begin(), E = LookupTable->data_end();
+ I != E;
+ ++I) {
+ ASTDeclContextNameLookupTrait::data_type Data = *I;
+ for (; Data.first != Data.second; ++Data.first) {
+ NamedDecl *ND = Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
+ if (!ND)
+ continue;
+
+ // Record this declaration.
+ FoundAnything = true;
+ if (DeclSet.insert(ND).second)
+ Decls[ND->getDeclName()].push_back(ND);
+ }
+ }
+
+ return FoundAnything && !VisitAll;
+ }
+ };
+}
+
void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
if (!DC->hasExternalVisibleStorage())
return;
-
- auto It = Lookups.find(DC);
- assert(It != Lookups.end() &&
- "have external visible storage but no lookup tables");
-
DeclsMap Decls;
- for (DeclID ID : It->second.Table.findAll()) {
- NamedDecl *ND = cast<NamedDecl>(GetDecl(ID));
- Decls[ND->getDeclName()].push_back(ND);
+ // Compute the declaration contexts we need to look into. Multiple such
+ // declaration contexts occur when two declaration contexts from disjoint
+ // modules get merged, e.g., when two namespaces with the same name are
+ // independently defined in separate modules.
+ SmallVector<const DeclContext *, 2> Contexts;
+ Contexts.push_back(DC);
+
+ if (DC->isNamespace()) {
+ KeyDeclsMap::iterator Key =
+ KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ if (Key != KeyDecls.end()) {
+ for (unsigned I = 0, N = Key->second.size(); I != N; ++I)
+ Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I])));
+ }
}
+ DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls,
+ /*VisitAll=*/DC->isFileContext());
+ ModuleMgr.visit(Visitor);
++NumVisibleDeclContextsRead;
for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
@@ -6410,12 +6553,6 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false);
}
-const serialization::reader::DeclContextLookupTable *
-ASTReader::getLoadedLookupTables(DeclContext *Primary) const {
- auto I = Lookups.find(Primary);
- return I == Lookups.end() ? nullptr : &I->second;
-}
-
/// \brief Under non-PCH compilation the consumer receives the objc methods
/// before receiving the implementation, and codegen depends on this.
/// We simulate this by deserializing and passing to consumer the methods of the
@@ -7247,36 +7384,6 @@ Module *ASTReader::getModule(unsigned ID) {
return getSubmodule(ID);
}
-ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &F, unsigned ID) {
- if (ID & 1) {
- // It's a module, look it up by submodule ID.
- auto I = GlobalSubmoduleMap.find(getGlobalSubmoduleID(F, ID >> 1));
- return I == GlobalSubmoduleMap.end() ? nullptr : I->second;
- } else {
- // It's a prefix (preamble, PCH, ...). Look it up by index.
- unsigned IndexFromEnd = ID >> 1;
- assert(IndexFromEnd && "got reference to unknown module file");
- return getModuleManager().pch_modules().end()[-IndexFromEnd];
- }
-}
-
-unsigned ASTReader::getModuleFileID(ModuleFile *F) {
- if (!F)
- return 1;
-
- // For a file representing a module, use the submodule ID of the top-level
- // module as the file ID. For any other kind of file, the number of such
- // files loaded beforehand will be the same on reload.
- // FIXME: Is this true even if we have an explicit module file and a PCH?
- if (F->isModule())
- return ((F->BaseSubmoduleID + NUM_PREDEF_SUBMODULE_IDS) << 1) | 1;
-
- auto PCHModules = getModuleManager().pch_modules();
- auto I = std::find(PCHModules.begin(), PCHModules.end(), F);
- assert(I != PCHModules.end() && "emitting reference to unknown file");
- return (I - PCHModules.end()) << 1;
-}
-
ExternalASTSource::ASTSourceDescriptor
ASTReader::getSourceDescriptor(const Module &M) {
StringRef Dir, Filename;
@@ -8325,8 +8432,6 @@ void ASTReader::FinishedDeserializing() {
for (auto Update : Updates) {
auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
auto ESI = FPT->getExtProtoInfo().ExceptionSpec;
- if (auto *Listener = Context.getASTMutationListener())
- Listener->ResolvedExceptionSpec(cast<FunctionDecl>(Update.second));
for (auto *Redecl : Update.second->redecls())
Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
}
OpenPOWER on IntegriCloud