diff options
Diffstat (limited to 'clang/lib/Serialization/ASTReader.cpp')
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 257 |
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); } |