Any chance this is what caused the following leak? http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-bootstrap/builds/8340/steps/check-clang%20asan/logs/stdio
Cheers, Rafael On 31 August 2015 at 18:17, Richard Smith via cfe-commits <cfe-commits@lists.llvm.org> wrote: > Author: rsmith > Date: Mon Aug 31 17:17:11 2015 > New Revision: 246497 > > URL: http://llvm.org/viewvc/llvm-project?rev=246497&view=rev > Log: > [modules] Rework serialized DeclContext lookup table management. Instead of > walking the loaded ModuleFiles looking for lookup tables for the context, > store > them all in one place, and merge them together if we find we have too many > (currently, more than 4). If we do merge, include the merged form in our > serialized lookup table, so that downstream readers never need to look at our > imports' tables. > > This gives a huge performance improvement to builds with very large numbers of > modules (in some cases, more than a 2x speedup was observed). > > Added: > cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h > Modified: > cfe/trunk/include/clang/Serialization/ASTBitCodes.h > cfe/trunk/include/clang/Serialization/ASTReader.h > cfe/trunk/include/clang/Serialization/ASTWriter.h > cfe/trunk/include/clang/Serialization/Module.h > cfe/trunk/lib/Serialization/ASTReader.cpp > cfe/trunk/lib/Serialization/ASTReaderDecl.cpp > cfe/trunk/lib/Serialization/ASTReaderInternals.h > cfe/trunk/lib/Serialization/ASTWriter.cpp > cfe/trunk/lib/Serialization/ASTWriterDecl.cpp > cfe/trunk/lib/Serialization/Module.cpp > cfe/trunk/test/Modules/cxx-templates.cpp > cfe/trunk/test/Modules/merge-using-decls.cpp > > Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original) > +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Mon Aug 31 17:17:11 > 2015 > @@ -1530,4 +1530,23 @@ namespace clang { > } > } // end namespace clang > > +namespace llvm { > + template <> struct DenseMapInfo<clang::serialization::DeclarationNameKey> { > + static clang::serialization::DeclarationNameKey getEmptyKey() { > + return clang::serialization::DeclarationNameKey(-1, 1); > + } > + static clang::serialization::DeclarationNameKey getTombstoneKey() { > + return clang::serialization::DeclarationNameKey(-1, 2); > + } > + static unsigned > + getHashValue(const clang::serialization::DeclarationNameKey &Key) { > + return Key.getHash(); > + } > + static bool isEqual(const clang::serialization::DeclarationNameKey &L, > + const clang::serialization::DeclarationNameKey &R) { > + return L == R; > + } > + }; > +} > + > #endif > > Modified: cfe/trunk/include/clang/Serialization/ASTReader.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Serialization/ASTReader.h (original) > +++ cfe/trunk/include/clang/Serialization/ASTReader.h Mon Aug 31 17:17:11 2015 > @@ -282,9 +282,8 @@ class ReadMethodPoolVisitor; > > namespace reader { > class ASTIdentifierLookupTrait; > - /// \brief The on-disk hash table used for the DeclContext's Name lookup > table. > - typedef llvm::OnDiskIterableChainedHashTable<ASTDeclContextNameLookupTrait> > - ASTDeclContextNameLookupTable; > + /// \brief The on-disk hash table(s) used for DeclContext name lookup. > + struct DeclContextLookupTable; > } > > } // end namespace serialization > @@ -507,6 +506,10 @@ private: > /// \brief Map from the TU to its lexical contents from each module file. > std::vector<std::pair<ModuleFile*, LexicalContents>> TULexicalDecls; > > + /// \brief Map from a DeclContext to its lookup tables. > + llvm::DenseMap<const DeclContext *, > + serialization::reader::DeclContextLookupTable> Lookups; > + > // Updates for visible decls can occur for other contexts than just the > // TU, and when we read those update records, the actual context may not > // be available yet, so have this pending map using the ID as a key. It > @@ -514,7 +517,6 @@ private: > struct PendingVisibleUpdate { > ModuleFile *Mod; > const unsigned char *Data; > - unsigned BucketOffset; > }; > typedef SmallVector<PendingVisibleUpdate, 1> DeclContextVisibleUpdates; > > @@ -1089,6 +1091,10 @@ public: > Visit(GetExistingDecl(ID)); > } > > + /// \brief Get the loaded lookup tables for \p Primary, if any. > + const serialization::reader::DeclContextLookupTable * > + getLoadedLookupTables(DeclContext *Primary) const; > + > private: > struct ImportedModule { > ModuleFile *Mod; > @@ -1870,6 +1876,13 @@ public: > /// Note: overrides method in ExternalASTSource > Module *getModule(unsigned ID) override; > > + /// \brief Retrieve the module file with a given local ID within the > specified > + /// ModuleFile. > + ModuleFile *getLocalModuleFile(ModuleFile &M, unsigned ID); > + > + /// \brief Get an ID for the given module file. > + unsigned getModuleFileID(ModuleFile *M); > + > /// \brief Return a descriptor for the corresponding module. > llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) > override; > /// \brief Return a descriptor for the module. > > Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Serialization/ASTWriter.h (original) > +++ cfe/trunk/include/clang/Serialization/ASTWriter.h Mon Aug 31 17:17:11 2015 > @@ -529,8 +529,8 @@ private: > bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC); > bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext > *DC); > > - uint32_t GenerateNameLookupTable(const DeclContext *DC, > - llvm::SmallVectorImpl<char> &LookupTable); > + void GenerateNameLookupTable(const DeclContext *DC, > + llvm::SmallVectorImpl<char> &LookupTable); > uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext > *DC); > uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext > *DC); > void WriteTypeDeclOffsets(); > @@ -849,6 +849,7 @@ public: > unsigned getExprImplicitCastAbbrev() const { return > ExprImplicitCastAbbrev; } > > bool hasChain() const { return Chain; } > + ASTReader *getChain() const { return Chain; } > > // ASTDeserializationListener implementation > void ReaderInitialized(ASTReader *Reader) override; > > Modified: cfe/trunk/include/clang/Serialization/Module.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/Module.h?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Serialization/Module.h (original) > +++ cfe/trunk/include/clang/Serialization/Module.h Mon Aug 31 17:17:11 2015 > @@ -50,14 +50,6 @@ enum ModuleKind { > MK_MainFile ///< File is a PCH file treated as the actual main file. > }; > > -/// \brief Information about the contents of a DeclContext. > -struct DeclContextInfo { > - DeclContextInfo() : NameLookupTableData() {} > - > - llvm::OnDiskIterableChainedHashTable<reader::ASTDeclContextNameLookupTrait> > - *NameLookupTableData; // an ASTDeclContextNameLookupTable. > -}; > - > /// \brief The input file that has been loaded from this AST file, along with > /// bools indicating whether this was an overridden buffer or if it was > /// out-of-date or not-found. > @@ -416,13 +408,6 @@ public: > /// indexed by the C++ ctor initializer list ID minus 1. > const uint32_t *CXXCtorInitializersOffsets; > > - typedef llvm::DenseMap<const DeclContext *, DeclContextInfo> > - DeclContextInfosMap; > - > - /// \brief Information about the lexical and visible declarations > - /// for each DeclContext. > - DeclContextInfosMap DeclContextInfos; > - > /// \brief Array of file-level DeclIDs sorted by file. > const serialization::DeclID *FileSortedDecls; > unsigned NumFileSortedDecls; > > Modified: cfe/trunk/lib/Serialization/ASTReader.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon Aug 31 17:17:11 2015 > @@ -20,6 +20,7 @@ > #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" > @@ -903,6 +904,13 @@ unsigned DeclarationNameKey::getHash() c > 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; > @@ -948,15 +956,15 @@ ASTDeclContextNameLookupTrait::ReadKey(c > return DeclarationNameKey(Kind, Data); > } > > -ASTDeclContextNameLookupTrait::data_type > -ASTDeclContextNameLookupTrait::ReadData(internal_key_type, > - const unsigned char *d, > - unsigned DataLen) { > +void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type, > + const unsigned char *d, > + unsigned DataLen, > + data_type &Val) { > using namespace llvm::support; > - unsigned NumDecls = DataLen / 4; > - LE32DeclID *Start = reinterpret_cast<LE32DeclID *>( > - const_cast<unsigned char *>(d)); > - return std::make_pair(Start, Start + NumDecls); > + for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) { > + uint32_t LocalID = endian::readNext<uint32_t, little, unaligned>(d); > + Val.insert(Reader.getGlobalDeclID(F, LocalID)); > + } > } > > bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, > @@ -1015,9 +1023,8 @@ bool ASTReader::ReadVisibleDeclContextSt > > // We can't safely determine the primary context yet, so delay attaching > the > // lookup table until we're done with recursive deserialization. > - unsigned BucketOffset = Record[0]; > - PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{ > - &M, (const unsigned char *)Blob.data(), BucketOffset}); > + auto *Data = (const unsigned char*)Blob.data(); > + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data}); > return false; > } > > @@ -2551,9 +2558,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, u > unsigned Idx = 0; > serialization::DeclID ID = ReadDeclID(F, Record, Idx); > auto *Data = (const unsigned char*)Blob.data(); > - unsigned BucketOffset = Record[Idx++]; > - PendingVisibleUpdates[ID].push_back( > - PendingVisibleUpdate{&F, Data, BucketOffset}); > + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data}); > // If we've already loaded the decl, perform the updates when we finish > // loading this block. > if (Decl *D = GetExistingDecl(ID)) > @@ -6354,196 +6359,48 @@ void ASTReader::FindFileRegionDecls(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() && > + assert(DC->hasExternalVisibleStorage() && DC == DC->getPrimaryContext() && > "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; > - 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); > + for (DeclID ID : It->second.Table.find(Name)) { > + NamedDecl *ND = cast<NamedDecl>(GetDecl(ID)); > + if (ND->getDeclName() == Name) > + Decls.push_back(ND); > + } > > ++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; > > - // 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]))); > - } > + for (DeclID ID : It->second.Table.findAll()) { > + NamedDecl *ND = cast<NamedDecl>(GetDecl(ID)); > + Decls[ND->getDeclName()].push_back(ND); > } > > - DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls, > - /*VisitAll=*/DC->isFileContext()); > - ModuleMgr.visit(Visitor); > ++NumVisibleDeclContextsRead; > > for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { > @@ -6552,6 +6409,12 @@ void ASTReader::completeVisibleDeclsMap( > 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 > @@ -7383,6 +7246,37 @@ 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()) > + // FIXME: BaseSubmoduleID appears to be off by one. > + return ((F->BaseSubmoduleID + 1) << 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; > @@ -8431,6 +8325,8 @@ 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); > } > > Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Aug 31 17:17:11 2015 > @@ -1489,6 +1489,8 @@ void ASTDeclReader::MergeDefinitionData( > Reader.PendingDefinitions.erase(MergeDD.Definition); > MergeDD.Definition->IsCompleteDefinition = false; > mergeDefinitionVisibility(DD.Definition, MergeDD.Definition); > + assert(Reader.Lookups.find(MergeDD.Definition) == Reader.Lookups.end() && > + "already loaded pending lookups for merged definition"); > } > > auto PFDI = Reader.PendingFakeDefinitionData.find(&DD); > @@ -3346,15 +3348,10 @@ void ASTReader::loadDeclUpdateRecords(se > PendingVisibleUpdates.erase(I); > > auto *DC = cast<DeclContext>(D)->getPrimaryContext(); > - for (const PendingVisibleUpdate &Update : VisibleUpdates) { > - auto *&LookupTable = > Update.Mod->DeclContextInfos[DC].NameLookupTableData; > - assert(!LookupTable && "multiple lookup tables for DC in module"); > - LookupTable = reader::ASTDeclContextNameLookupTable::Create( > - Update.Data + Update.BucketOffset, > - Update.Data + sizeof(uint32_t), > - Update.Data, > + for (const PendingVisibleUpdate &Update : VisibleUpdates) > + Lookups[DC].Table.add( > + Update.Mod, Update.Data, > reader::ASTDeclContextNameLookupTrait(*this, *Update.Mod)); > - } > DC->setHasExternalVisibleStorage(true); > } > > > Modified: cfe/trunk/lib/Serialization/ASTReaderInternals.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderInternals.h?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTReaderInternals.h (original) > +++ cfe/trunk/lib/Serialization/ASTReaderInternals.h Mon Aug 31 17:17:11 2015 > @@ -15,8 +15,12 @@ > > #include "clang/AST/DeclarationName.h" > #include "clang/Serialization/ASTBitCodes.h" > +#include "llvm/ADT/DenseSet.h" > +#include "llvm/ADT/PointerUnion.h" > +#include "llvm/ADT/TinyPtrVector.h" > #include "llvm/Support/Endian.h" > #include "llvm/Support/OnDiskHashTable.h" > +#include "MultiOnDiskHashTable.h" > #include <utility> > > namespace clang { > @@ -39,14 +43,15 @@ class ASTDeclContextNameLookupTrait { > ModuleFile &F; > > public: > - /// \brief Pair of begin/end iterators for DeclIDs. > - /// > - /// Note that these declaration IDs are local to the module that contains > this > - /// particular lookup t > - typedef llvm::support::ulittle32_t LE32DeclID; > - typedef std::pair<LE32DeclID *, LE32DeclID *> data_type; > + // Maximum number of lookup tables we allow before condensing the tables. > + static const int MaxTables = 4; > + > + /// The lookup result is a list of global declaration IDs. > + // FIXME: LLVM doesn't really have a good data structure for this. > + typedef llvm::DenseSet<DeclID> data_type; > typedef unsigned hash_value_type; > typedef unsigned offset_type; > + typedef ModuleFile *file_type; > > typedef DeclarationName external_key_type; > typedef DeclarationNameKey internal_key_type; > @@ -54,8 +59,7 @@ public: > explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, ModuleFile &F) > : Reader(Reader), F(F) { } > > - static bool EqualKey(const internal_key_type& a, > - const internal_key_type& b) { > + static bool EqualKey(const internal_key_type &a, const internal_key_type > &b) { > return a == b; > } > > @@ -71,8 +75,18 @@ public: > > internal_key_type ReadKey(const unsigned char *d, unsigned); > > - data_type ReadData(internal_key_type, const unsigned char *d, > - unsigned DataLen); > + void ReadDataInto(internal_key_type, const unsigned char *d, > + unsigned DataLen, data_type &Val); > + > + static void MergeDataInto(const data_type &From, data_type &To) { > + To.insert(From.begin(), From.end()); > + } > + > + file_type ReadFileRef(const unsigned char *&d); > +}; > + > +struct DeclContextLookupTable { > + MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> Table; > }; > > /// \brief Base class for the trait describing the on-disk hash table for the > > Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Aug 31 17:17:11 2015 > @@ -13,6 +13,8 @@ > > #include "clang/Serialization/ASTWriter.h" > #include "ASTCommon.h" > +#include "ASTReaderInternals.h" > +#include "MultiOnDiskHashTable.h" > #include "clang/AST/ASTContext.h" > #include "clang/AST/Decl.h" > #include "clang/AST/DeclContextInternals.h" > @@ -3338,12 +3340,14 @@ namespace { > // Trait used for the on-disk hash table used in the method pool. > class ASTDeclContextNameLookupTrait { > ASTWriter &Writer; > + llvm::SmallVector<DeclID, 64> DeclIDs; > > public: > typedef DeclarationNameKey key_type; > typedef key_type key_type_ref; > > - typedef DeclContext::lookup_result data_type; > + /// A start and end index into DeclIDs, representing a sequence of decls. > + typedef std::pair<unsigned, unsigned> data_type; > typedef const data_type& data_type_ref; > > typedef unsigned hash_value_type; > @@ -3351,10 +3355,40 @@ public: > > explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) > { } > > + template<typename Coll> > + data_type getData(const Coll &Decls) { > + unsigned Start = DeclIDs.size(); > + for (NamedDecl *D : Decls) { > + DeclIDs.push_back( > + Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), D))); > + } > + return std::make_pair(Start, DeclIDs.size()); > + } > + > + data_type ImportData(const > reader::ASTDeclContextNameLookupTrait::data_type &FromReader) { > + unsigned Start = DeclIDs.size(); > + for (auto ID : FromReader) > + DeclIDs.push_back(ID); > + return std::make_pair(Start, DeclIDs.size()); > + } > + > + static bool EqualKey(key_type_ref a, key_type_ref b) { > + return a == b; > + } > + > hash_value_type ComputeHash(DeclarationNameKey Name) { > return Name.getHash(); > } > > + void EmitFileRef(raw_ostream &Out, ModuleFile *F) const { > + assert(Writer.hasChain() && > + "have reference to loaded module file but no chain?"); > + > + using namespace llvm::support; > + endian::Writer<little>(Out) > + .write<uint32_t>(Writer.getChain()->getModuleFileID(F)); > + } > + > std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &Out, > DeclarationNameKey Name, > data_type_ref Lookup) { > @@ -3381,7 +3415,9 @@ public: > LE.write<uint16_t>(KeyLen); > > // 4 bytes for each DeclID. > - unsigned DataLen = 4 * Lookup.size(); > + unsigned DataLen = 4 * (Lookup.second - Lookup.first); > + assert(uint16_t(DataLen) == DataLen && > + "too many decls for serialized lookup result"); > LE.write<uint16_t>(DataLen); > > return std::make_pair(KeyLen, DataLen); > @@ -3421,11 +3457,8 @@ public: > using namespace llvm::support; > endian::Writer<little> LE(Out); > uint64_t Start = Out.tell(); (void)Start; > - for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end(); > - I != E; ++I) > - LE.write<uint32_t>( > - Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), > *I))); > - > + for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) > + LE.write<uint32_t>(DeclIDs[I]); > assert(Out.tell() - Start == DataLen && "Data length is wrong"); > } > }; > @@ -3445,7 +3478,7 @@ bool ASTWriter::isLookupResultEntirelyEx > return true; > } > > -uint32_t > +void > ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC, > llvm::SmallVectorImpl<char> &LookupTable) > { > assert(!ConstDC->HasLazyLocalLexicalLookups && > @@ -3457,8 +3490,8 @@ ASTWriter::GenerateNameLookupTable(const > assert(DC == DC->getPrimaryContext() && "only primary DC has lookup > table"); > > // Create the on-disk hash table representation. > - llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> > - Generator; > + MultiOnDiskHashTableGenerator<reader::ASTDeclContextNameLookupTrait, > + ASTDeclContextNameLookupTrait> Generator; > ASTDeclContextNameLookupTrait Trait(*this); > > // The first step is to collect the declaration names which we need to > @@ -3593,7 +3626,7 @@ ASTWriter::GenerateNameLookupTable(const > > switch (Name.getNameKind()) { > default: > - Generator.insert(Name, Result, Trait); > + Generator.insert(Name, Trait.getData(Result), Trait); > break; > > case DeclarationName::CXXConstructorName: > @@ -3611,17 +3644,15 @@ ASTWriter::GenerateNameLookupTable(const > // the key, only the kind of name is used. > if (!ConstructorDecls.empty()) > Generator.insert(ConstructorDecls.front()->getDeclName(), > - DeclContext::lookup_result(ConstructorDecls), Trait); > + Trait.getData(ConstructorDecls), Trait); > if (!ConversionDecls.empty()) > Generator.insert(ConversionDecls.front()->getDeclName(), > - DeclContext::lookup_result(ConversionDecls), Trait); > + Trait.getData(ConversionDecls), Trait); > > - // Create the on-disk hash table in a buffer. > - llvm::raw_svector_ostream Out(LookupTable); > - // Make sure that no bucket is at offset 0 > - using namespace llvm::support; > - endian::Writer<little>(Out).write<uint32_t>(0); > - return Generator.Emit(Out, Trait); > + // Create the on-disk hash table. Also emit the existing imported and > + // merged table if there is one. > + auto *Lookups = Chain ? Chain->getLoadedLookupTables(DC) : nullptr; > + Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr); > } > > /// \brief Write the block containing all of the declaration IDs > @@ -3704,12 +3735,11 @@ uint64_t ASTWriter::WriteDeclContextVisi > > // Create the on-disk hash table in a buffer. > SmallString<4096> LookupTable; > - uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); > + GenerateNameLookupTable(DC, LookupTable); > > // Write the lookup table > RecordData Record; > Record.push_back(DECL_CONTEXT_VISIBLE); > - Record.push_back(BucketOffset); > Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record, > LookupTable); > ++NumVisibleDeclContexts; > @@ -3732,7 +3762,7 @@ void ASTWriter::WriteDeclContextVisibleU > > // Create the on-disk hash table in a buffer. > SmallString<4096> LookupTable; > - uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); > + GenerateNameLookupTable(DC, LookupTable); > > // If we're updating a namespace, select a key declaration as the key for > the > // update record; those are the only ones that will be checked on reload. > @@ -3743,7 +3773,6 @@ void ASTWriter::WriteDeclContextVisibleU > RecordData Record; > Record.push_back(UPDATE_VISIBLE); > Record.push_back(getDeclID(cast<Decl>(DC))); > - Record.push_back(BucketOffset); > Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable); > } > > @@ -4207,7 +4236,6 @@ void ASTWriter::WriteASTCore(Sema &SemaR > Abv = new llvm::BitCodeAbbrev(); > Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); > Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); > - Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 32)); > Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); > UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv); > WriteDeclContextVisibleUpdate(TU); > > Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Mon Aug 31 17:17:11 2015 > @@ -2049,7 +2049,6 @@ void ASTWriter::WriteDeclAbbrevs() { > > Abv = new BitCodeAbbrev(); > Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE)); > - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); > Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); > DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(Abv); > } > > Modified: cfe/trunk/lib/Serialization/Module.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/Module.cpp?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/Module.cpp (original) > +++ cfe/trunk/lib/Serialization/Module.cpp Mon Aug 31 17:17:11 2015 > @@ -45,13 +45,6 @@ ModuleFile::ModuleFile(ModuleKind Kind, > {} > > ModuleFile::~ModuleFile() { > - for (DeclContextInfosMap::iterator I = DeclContextInfos.begin(), > - E = DeclContextInfos.end(); > - I != E; ++I) { > - if (I->second.NameLookupTableData) > - delete I->second.NameLookupTableData; > - } > - > delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable); > delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable); > delete static_cast<ASTSelectorLookupTable *>(SelectorLookupTable); > > Added: cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h?rev=246497&view=auto > ============================================================================== > --- cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h (added) > +++ cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h Mon Aug 31 17:17:11 > 2015 > @@ -0,0 +1,318 @@ > +//===--- MultiOnDiskHashTable.h - Merged set of hash tables -----*- C++ > -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// This file provides a hash table data structure suitable for incremental > and > +// distributed storage across a set of files. > +// > +// Multiple hash tables from different files are implicitly merged to > improve > +// performance, and on reload the merged table will override those from > other > +// files. > +// > +//===----------------------------------------------------------------------===// > +#ifndef LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H > +#define LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H > + > +#include "llvm/ADT/PointerUnion.h" > +#include "llvm/Support/EndianStream.h" > +#include "llvm/Support/OnDiskHashTable.h" > + > +namespace clang { > +namespace serialization { > + > +class ModuleFile; > + > +/// \brief A collection of on-disk hash tables, merged when relevant for > performance. > +template<typename Info> class MultiOnDiskHashTable { > +public: > + /// A handle to a file, used when overriding tables. > + typedef typename Info::file_type file_type; > + /// A pointer to an on-disk representation of the hash table. > + typedef const unsigned char *storage_type; > + > + typedef typename Info::external_key_type external_key_type; > + typedef typename Info::internal_key_type internal_key_type; > + typedef typename Info::data_type data_type; > + typedef unsigned hash_value_type; > + > +private: > + /// \brief A hash table stored on disk. > + struct OnDiskTable { > + typedef llvm::OnDiskIterableChainedHashTable<Info> HashTable; > + > + file_type File; > + HashTable Table; > + > + OnDiskTable(file_type File, unsigned NumBuckets, unsigned NumEntries, > + storage_type Buckets, storage_type Payload, storage_type > Base, > + const Info &InfoObj) > + : File(File), > + Table(NumBuckets, NumEntries, Buckets, Payload, Base, InfoObj) {} > + }; > + > + struct MergedTable { > + std::vector<file_type> Files; > + llvm::DenseMap<internal_key_type, data_type> Data; > + }; > + > + typedef llvm::PointerUnion<OnDiskTable*, MergedTable*> Table; > + typedef llvm::TinyPtrVector<void*> TableVector; > + > + /// \brief The current set of on-disk and merged tables. > + /// We manually store the opaque value of the Table because TinyPtrVector > + /// can't cope with holding a PointerUnion directly. > + /// There can be at most one MergedTable in this vector, and if present, > + /// it is the first table. > + TableVector Tables; > + > + /// \brief Files corresponding to overridden tables that we've not yet > + /// discarded. > + llvm::TinyPtrVector<file_type> PendingOverrides; > + > + struct AsOnDiskTable { > + typedef OnDiskTable *result_type; > + result_type operator()(void *P) const { > + return Table::getFromOpaqueValue(P).template get<OnDiskTable *>(); > + } > + }; > + typedef llvm::mapped_iterator<TableVector::iterator, AsOnDiskTable> > + table_iterator; > + typedef llvm::iterator_range<table_iterator> table_range; > + > + /// \brief The current set of on-disk tables. > + table_range tables() { > + auto Begin = Tables.begin(), End = Tables.end(); > + if (getMergedTable()) > + ++Begin; > + return llvm::make_range(llvm::map_iterator(Begin, AsOnDiskTable()), > + llvm::map_iterator(End, AsOnDiskTable())); > + } > + > + MergedTable *getMergedTable() const { > + // If we already have a merged table, it's the first one. > + return Tables.empty() ? nullptr : > Table::getFromOpaqueValue(*Tables.begin()) > + .template dyn_cast<MergedTable*>(); > + } > + > + /// \brief Delete all our current on-disk tables. > + void clear() { > + if (auto *M = getMergedTable()) > + delete M; > + for (auto *T : tables()) > + delete T; > + } > + > + void removeOverriddenTables() { > + llvm::DenseSet<file_type> Files; > + Files.insert(PendingOverrides.begin(), PendingOverrides.end()); > + Tables.erase( > + std::remove_if(tables().begin().getCurrent(), Tables.end(), [&](void > *T) -> bool { > + auto *ODT = Table::getFromOpaqueValue(T).template > get<OnDiskTable*>(); > + return Files.count(ODT->File); > + }), Tables.end()); > + PendingOverrides.clear(); > + } > + > + void condense() { > + MergedTable *Merged = getMergedTable(); > + if (!Merged) > + Merged = new MergedTable; > + > + // Read in all the tables and merge them together. > + // FIXME: Be smarter about which tables we merge. > + for (auto *ODT : tables()) { > + auto &HT = ODT->Table; > + Info &InfoObj = HT.getInfoObj(); > + > + for (auto I = HT.data_begin(), E = HT.data_end(); I != E; ++I) { > + auto *LocalPtr = I.getItem(); > + > + // FIXME: Don't rely on the OnDiskHashTable format here. > + auto L = InfoObj.ReadKeyDataLength(LocalPtr); > + const internal_key_type &Key = InfoObj.ReadKey(LocalPtr, L.first); > + InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second, > + Merged->Data[Key]); > + } > + > + Merged->Files.push_back(ODT->File); > + delete ODT; > + } > + > + Tables.clear(); > + Tables.push_back(Table(Merged).getOpaqueValue()); > + } > + > + /// The generator is permitted to read our merged table. > + template<typename ReaderInfo, typename WriterInfo> > + friend class MultiOnDiskHashTableGenerator; > + > +public: > + MultiOnDiskHashTable() {} > + MultiOnDiskHashTable(MultiOnDiskHashTable &&O) > + : Tables(std::move(O.Tables)), > + PendingOverrides(std::move(O.PendingOverrides)) { > + O.Tables.clear(); > + } > + MultiOnDiskHashTable &operator=(MultiOnDiskHashTable &&O) { > + if (&O == this) > + return *this; > + clear(); > + Tables = std::move(O.Tables); > + O.Tables.clear(); > + PendingOverrides = std::move(O.PendingOverrides); > + return *this; > + } > + ~MultiOnDiskHashTable() { clear(); } > + > + /// \brief Add the table \p Data loaded from file \p File. > + void add(file_type File, storage_type Data, Info InfoObj = Info()) { > + using namespace llvm::support; > + storage_type Ptr = Data; > + > + uint32_t BucketOffset = endian::readNext<uint32_t, little, > unaligned>(Ptr); > + > + // Read the list of overridden files. > + uint32_t NumFiles = endian::readNext<uint32_t, little, unaligned>(Ptr); > + // FIXME: Add a reserve() to TinyPtrVector so that we don't need to make > + // an additional copy. > + llvm::SmallVector<file_type, 16> OverriddenFiles; > + OverriddenFiles.reserve(NumFiles); > + for (/**/; NumFiles != 0; --NumFiles) > + OverriddenFiles.push_back(InfoObj.ReadFileRef(Ptr)); > + PendingOverrides.insert(PendingOverrides.end(), OverriddenFiles.begin(), > + OverriddenFiles.end()); > + > + // Read the OnDiskChainedHashTable header. > + storage_type Buckets = Data + BucketOffset; > + auto NumBucketsAndEntries = > + OnDiskTable::HashTable::readNumBucketsAndEntries(Buckets); > + > + // Register the table. > + Table NewTable = new OnDiskTable(File, NumBucketsAndEntries.first, > + NumBucketsAndEntries.second, > + Buckets, Ptr, Data, std::move(InfoObj)); > + Tables.push_back(NewTable.getOpaqueValue()); > + } > + > + /// \brief Find and read the lookup results for \p EKey. > + data_type find(const external_key_type &EKey) { > + data_type Result; > + > + if (!PendingOverrides.empty()) > + removeOverriddenTables(); > + > + if (Tables.size() > Info::MaxTables) > + condense(); > + > + internal_key_type Key = Info::GetInternalKey(EKey); > + auto KeyHash = Info::ComputeHash(Key); > + > + if (MergedTable *M = getMergedTable()) { > + auto It = M->Data.find(Key); > + if (It != M->Data.end()) > + Result = It->second; > + } > + > + for (auto *ODT : tables()) { > + auto &HT = ODT->Table; > + auto It = HT.find_hashed(Key, KeyHash); > + if (It != HT.end()) > + HT.getInfoObj().ReadDataInto(Key, It.getDataPtr(), It.getDataLen(), > + Result); > + } > + > + return Result; > + } > + > + /// \brief Read all the lookup results into a single value. This only makes > + /// sense if merging values across keys is meaningful. > + data_type findAll() { > + data_type Result; > + > + if (!PendingOverrides.empty()) > + removeOverriddenTables(); > + > + if (MergedTable *M = getMergedTable()) { > + for (auto &KV : M->Data) > + Info::MergeDataInto(KV.second, Result); > + } > + > + for (auto *ODT : tables()) { > + auto &HT = ODT->Table; > + Info &InfoObj = HT.getInfoObj(); > + for (auto I = HT.data_begin(), E = HT.data_end(); I != E; ++I) { > + auto *LocalPtr = I.getItem(); > + > + // FIXME: Don't rely on the OnDiskHashTable format here. > + auto L = InfoObj.ReadKeyDataLength(LocalPtr); > + const internal_key_type &Key = InfoObj.ReadKey(LocalPtr, L.first); > + InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second, Result); > + } > + } > + > + return Result; > + } > +}; > + > +/// \brief Writer for the on-disk hash table. > +template<typename ReaderInfo, typename WriterInfo> > +class MultiOnDiskHashTableGenerator { > + typedef MultiOnDiskHashTable<ReaderInfo> BaseTable; > + typedef llvm::OnDiskChainedHashTableGenerator<WriterInfo> Generator; > + > + Generator Gen; > + > +public: > + MultiOnDiskHashTableGenerator() : Gen() {} > + > + void insert(typename WriterInfo::key_type_ref Key, > + typename WriterInfo::data_type_ref Data, WriterInfo &Info) { > + Gen.insert(Key, Data, Info); > + } > + > + void emit(llvm::SmallVectorImpl<char> &Out, WriterInfo &Info, > + const BaseTable *Base) { > + using namespace llvm::support; > + llvm::raw_svector_ostream OutStream(Out); > + > + // Write our header information. > + { > + endian::Writer<little> Writer(OutStream); > + > + // Reserve four bytes for the bucket offset. > + Writer.write<uint32_t>(0); > + > + if (auto *Merged = Base ? Base->getMergedTable() : nullptr) { > + // Write list of overridden files. > + Writer.write<uint32_t>(Merged->Files.size()); > + for (const auto &F : Merged->Files) > + Info.EmitFileRef(OutStream, F); > + > + // Add all merged entries from Base to the generator. > + for (auto &KV : Merged->Data) { > + if (!Gen.contains(KV.first, Info)) > + Gen.insert(KV.first, Info.ImportData(KV.second), Info); > + } > + } else { > + Writer.write<uint32_t>(0); > + } > + } > + > + // Write the table itself. > + uint32_t BucketOffset = Gen.Emit(OutStream, Info); > + > + // Replace the first four bytes with the bucket offset. > + endian::write32le(Out.data(), BucketOffset); > + } > +}; > + > +} // end namespace clang::serialization > +} // end namespace clang > + > + > +#endif > > Modified: cfe/trunk/test/Modules/cxx-templates.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cxx-templates.cpp?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/test/Modules/cxx-templates.cpp (original) > +++ cfe/trunk/test/Modules/cxx-templates.cpp Mon Aug 31 17:17:11 2015 > @@ -29,14 +29,14 @@ void g() { > f<int>(); > f(); // expected-error {{no matching function}} > // expected-note@Inputs/cxx-templates-b.h:3 {{couldn't infer template > argument}} > - // expected-note@Inputs/cxx-templates-b.h:4 {{requires single argument}} > + // expected-note-re@Inputs/cxx-templates-a.h:4 {{requires {{single|1}} > argument}} > > N::f(0); > N::f<double>(1.0); > N::f<int>(); > N::f(); // expected-error {{no matching function}} > // expected-note@Inputs/cxx-templates-b.h:6 {{couldn't infer template > argument}} > - // expected-note@Inputs/cxx-templates-b.h:7 {{requires single argument}} > + // expected-note-re@Inputs/cxx-templates-a.h:7 {{requires {{single|1}} > argument}} > > template_param_kinds_1<0>(); // ok, from cxx-templates-a.h > template_param_kinds_1<int>(); // ok, from cxx-templates-b.h > @@ -179,10 +179,14 @@ namespace Std { > > // CHECK-GLOBAL: DeclarationName 'f' > // CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f' > +// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f' > +// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f' > // CHECK-GLOBAL-NEXT: `-FunctionTemplate {{.*}} 'f' > > // CHECK-NAMESPACE-N: DeclarationName 'f' > // CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f' > +// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f' > +// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f' > // CHECK-NAMESPACE-N-NEXT: `-FunctionTemplate {{.*}} 'f' > > // CHECK-DUMP: ClassTemplateDecl {{.*}} > <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in > cxx_templates_common SomeTemplate > > Modified: cfe/trunk/test/Modules/merge-using-decls.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/merge-using-decls.cpp?rev=246497&r1=246496&r2=246497&view=diff > ============================================================================== > --- cfe/trunk/test/Modules/merge-using-decls.cpp (original) > +++ cfe/trunk/test/Modules/merge-using-decls.cpp Mon Aug 31 17:17:11 2015 > @@ -31,7 +31,9 @@ template int UseAll<YA>(); > template int UseAll<YB>(); > template int UseAll<Y>(); > > -#if ORDER == 1 > +// Which of these two sets of diagnostics is chosen is not important. It's OK > +// if this varies with ORDER, but it must be consistent across runs. > +#if 1 > // Here, we're instantiating the definition from 'A' and merging the > definition > // from 'B' into it. > > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits