On Sat, Aug 22, 2015 at 1:16 AM, Vassil Vassilev <vvasi...@cern.ch> wrote:
> On 22/08/15 03:47, Richard Smith via cfe-commits wrote: > >> Author: rsmith >> Date: Fri Aug 21 20:47:18 2015 >> New Revision: 245779 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=245779&view=rev >> Log: >> [modules] Rearrange how redeclaration chains are loaded, to remove a walk >> over >> all modules and reduce the number of declarations we load when loading a >> redeclaration chain. >> >> The new approach is: >> * when loading the first declaration of an entity within a module file, >> we >> first load all declarations of the entity that were imported into that >> module file, and then load all the other declarations of that entity >> from >> that module file and build a suitable decl chain from them >> * when loading any other declaration of an entity, we first load the >> first >> declaration from the same module file >> >> As before, we complete redecl chains through name lookup where necessary. >> >> To make this work, I also had to change the way that template >> specializations >> are stored -- it no longer suffices to track only canonical >> specializations; we >> now emit all "first local" declarations when emitting a list of >> specializations >> for a template. >> >> On one testcase with several thousand imported module files, this reduces >> the >> total runtime by 72%. >> > Very nice! > Does it reduce the depth of the redecl chains when merging? I.e. does this > mean memory footprint reduction too? I wouldn't expect any difference there, and in any case, I think this would only affect the stack depth, which is typically bounded anyway since we normally build modules on a separate thread. > Modified: >> cfe/trunk/include/clang/Serialization/ASTWriter.h >> cfe/trunk/lib/Serialization/ASTReader.cpp >> cfe/trunk/lib/Serialization/ASTReaderDecl.cpp >> cfe/trunk/lib/Serialization/ASTWriter.cpp >> cfe/trunk/lib/Serialization/ASTWriterDecl.cpp >> cfe/trunk/test/Modules/cxx-templates.cpp >> >> Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=245779&r1=245778&r2=245779&view=diff >> >> ============================================================================== >> --- cfe/trunk/include/clang/Serialization/ASTWriter.h (original) >> +++ cfe/trunk/include/clang/Serialization/ASTWriter.h Fri Aug 21 20:47:18 >> 2015 >> @@ -405,6 +405,10 @@ private: >> /// \brief The set of declarations that may have redeclaration chains >> that >> /// need to be serialized. >> llvm::SmallVector<const Decl *, 16> Redeclarations; >> + >> + /// \brief A cache of the first local declaration for "interesting" >> + /// redeclaration chains. >> + llvm::DenseMap<const Decl *, const Decl *> FirstLocalDeclCache; >> /// \brief Statements that >> we've encountered while serializing a >> /// declaration or type. >> @@ -676,6 +680,10 @@ public: >> const ASTTemplateArgumentListInfo >> *ASTTemplArgList, >> RecordDataImpl &Record); >> + /// \brief Find the first local declaration of a given local >> redeclarable >> + /// decl. >> + const Decl *getFirstLocalDecl(const Decl *D); >> + >> /// \brief Emit a reference to a declaration. >> void AddDeclRef(const Decl *D, RecordDataImpl &Record); >> @@ -857,12 +865,6 @@ public: >> void CompletedTagDefinition(const TagDecl *D) override; >> void AddedVisibleDecl(const DeclContext *DC, const Decl *D) override; >> void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) >> override; >> - void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, >> - const ClassTemplateSpecializationDecl *D) >> override; >> - void AddedCXXTemplateSpecialization(const VarTemplateDecl *TD, >> - const VarTemplateSpecializationDecl *D) >> override; >> - void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, >> - const FunctionDecl *D) override; >> void ResolvedExceptionSpec(const FunctionDecl *FD) override; >> void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) >> override; >> void ResolvedOperatorDelete(const CXXDestructorDecl *DD, >> >> Modified: cfe/trunk/lib/Serialization/ASTReader.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=245779&r1=245778&r2=245779&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) >> +++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Aug 21 20:47:18 2015 >> @@ -8123,11 +8123,8 @@ void ASTReader::finishPendingActions() { >> PendingIncompleteDeclChains.clear(); >> // Load pending declaration chains. >> - for (unsigned I = 0; I != PendingDeclChains.size(); ++I) { >> - PendingDeclChainsKnown.erase(PendingDeclChains[I]); >> + for (unsigned I = 0; I != PendingDeclChains.size(); ++I) >> loadPendingDeclChain(PendingDeclChains[I]); >> - } >> - assert(PendingDeclChainsKnown.empty()); >> PendingDeclChains.clear(); >> assert(RedeclsDeserialized.empty() && "some redecls not wired >> up"); >> >> Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=245779&r1=245778&r2=245779&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) >> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Aug 21 20:47:18 2015 >> @@ -147,12 +147,6 @@ namespace clang { >> } >> ~RedeclarableResult() { >> - if (FirstID && Owning && >> - isRedeclarableDeclKind(LoadedDecl->getKind())) { >> - auto Canon = Reader.GetDecl(FirstID)->getCanonicalDecl(); >> - if (Reader.PendingDeclChainsKnown.insert(Canon).second) >> - Reader.PendingDeclChains.push_back(Canon); >> - } >> } >> /// \brief Note that a RedeclarableDecl is not actually >> redeclarable. >> @@ -2186,23 +2180,33 @@ ASTDeclReader::RedeclarableResult >> ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { >> DeclID FirstDeclID = ReadDeclID(Record, Idx); >> Decl *MergeWith = nullptr; >> + >> bool IsKeyDecl = ThisDeclID == FirstDeclID; >> + bool IsFirstLocalDecl = false; >> // 0 indicates that this declaration was the only declaration of >> its entity, >> // and is used for space optimization. >> if (FirstDeclID == 0) { >> FirstDeclID = ThisDeclID; >> IsKeyDecl = true; >> + IsFirstLocalDecl = true; >> } else if (unsigned N = Record[Idx++]) { >> - IsKeyDecl = false; >> + // This declaration was the first local declaration, but may have >> imported >> + // other declarations. >> + IsKeyDecl = N == 1; >> + IsFirstLocalDecl = true; >> // We have some declarations that must be before us in our >> redeclaration >> // chain. Read them now, and remember that we ought to merge with >> one of >> // them. >> // FIXME: Provide a known merge target to the second and subsequent >> such >> // declaration. >> - for (unsigned I = 0; I != N; ++I) >> + for (unsigned I = 0; I != N - 1; ++I) >> MergeWith = ReadDecl(Record, Idx/*, MergeWith*/); >> + } else { >> + // This declaration was not the first local declaration. Read the >> first >> + // local declaration now, to trigger the import of other >> redeclarations. >> + (void)ReadDecl(Record, Idx); >> } >> T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID)); >> @@ -2214,13 +2218,21 @@ ASTDeclReader::VisitRedeclarable(Redecla >> D->RedeclLink = Redeclarable<T>::PreviousDeclLink(FirstDecl); >> D->First = FirstDecl->getCanonicalDecl(); >> } >> - >> + >> // Note that this declaration has been deserialized. >> - Reader.RedeclsDeserialized.insert(static_cast<T *>(D)); >> - >> + T *DAsT = static_cast<T*>(D); >> + Reader.RedeclsDeserialized.insert(DAsT); >> + >> + // Note that we need to load local redeclarations of this decl and >> build a >> + // decl chain for them. This must happen *after* we perform the >> preloading >> + // above; this ensures that the redeclaration chain is built in the >> correct >> + // order. >> + if (IsFirstLocalDecl) >> + Reader.PendingDeclChains.push_back(DAsT); >> + >> // The result structure takes care to note that we need to load the >> // other declaration chains for this ID. >> - return RedeclarableResult(Reader, FirstDeclID, static_cast<T *>(D), >> MergeWith, >> + return RedeclarableResult(Reader, FirstDeclID, DAsT, MergeWith, >> IsKeyDecl); >> } >> @@ -2330,11 +2342,8 @@ void ASTDeclReader::mergeRedeclarable(Re >> TemplatePatternID, Redecl.isKeyDecl()); >> // If this declaration is a key declaration, make a note of that. >> - if (Redecl.isKeyDecl()) { >> + if (Redecl.isKeyDecl()) >> Reader.KeyDecls[ExistingCanon].push_back(Redecl.getFirstID()); >> - if (Reader.PendingDeclChainsKnown.insert(ExistingCanon).second) >> - Reader.PendingDeclChains.push_back(ExistingCanon); >> - } >> } >> } >> @@ -3424,15 +3433,12 @@ namespace { >> ASTReader &Reader; >> SmallVectorImpl<DeclID> &SearchDecls; >> llvm::SmallPtrSetImpl<Decl *> &Deserialized; >> - GlobalDeclID CanonID; >> SmallVector<Decl *, 4> Chain; >> public: >> RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> >> &SearchDecls, >> - llvm::SmallPtrSetImpl<Decl *> &Deserialized, >> - GlobalDeclID CanonID) >> - : Reader(Reader), SearchDecls(SearchDecls), >> Deserialized(Deserialized), >> - CanonID(CanonID) { >> + llvm::SmallPtrSetImpl<Decl *> &Deserialized) >> + : Reader(Reader), SearchDecls(SearchDecls), >> Deserialized(Deserialized) { >> assert(std::is_sorted(SearchDecls.begin(), SearchDecls.end())); >> } >> @@ -3518,10 +3524,10 @@ namespace { >> break; >> } >> - if (LocalSearchDeclID && LocalSearchDeclID != CanonID) { >> + assert(LocalSearchDeclID); >> + if (LocalSearchDeclID) { >> // If the search decl was from this module, add it to the chain. >> // Note, the chain is sorted from newest to oldest, so this >> goes last. >> - // We exclude the canonical declaration; it implicitly goes at >> the end. >> addToChain(Reader.GetDecl(LocalSearchDeclID)); >> } >> @@ -3531,26 +3537,14 @@ namespace { >> }; >> } >> -void ASTReader::loadPendingDeclChain(Decl *CanonDecl) { >> - // The decl might have been merged into something else after being >> added to >> - // our list. If it was, just skip it. >> - if (!CanonDecl->isCanonicalDecl()) >> - return; >> - >> +void ASTReader::loadPendingDeclChain(Decl *FirstLocal) { >> // Determine the set of declaration IDs we'll be searching for. >> - SmallVector<DeclID, 16> SearchDecls; >> - GlobalDeclID CanonID = CanonDecl->getGlobalID(); >> - if (CanonID) >> - SearchDecls.push_back(CanonDecl->getGlobalID()); // Always first. >> - KeyDeclsMap::iterator KeyPos = KeyDecls.find(CanonDecl); >> - if (KeyPos != KeyDecls.end()) >> - SearchDecls.append(KeyPos->second.begin(), KeyPos->second.end()); >> - llvm::array_pod_sort(SearchDecls.begin(), SearchDecls.end()); >> + SmallVector<DeclID, 1> SearchDecls; >> + SearchDecls.push_back(FirstLocal->getGlobalID()); >> // Build up the list of redeclarations. >> - RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, >> CanonID); >> - ModuleMgr.visit(Visitor); >> - RedeclsDeserialized.erase(CanonDecl); >> + RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized); >> + Visitor(*getOwningModuleFile(FirstLocal)); >> // Retrieve the chains. >> ArrayRef<Decl *> Chain = Visitor.getChain(); >> @@ -3561,11 +3555,14 @@ void ASTReader::loadPendingDeclChain(Dec >> // >> // FIXME: We have three different dispatches on decl kind here; maybe >> // we should instead generate one loop per kind and dispatch up-front? >> + Decl *CanonDecl = FirstLocal->getCanonicalDecl(); >> Decl *MostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl); >> if (!MostRecent) >> MostRecent = CanonDecl; >> for (unsigned I = 0, N = Chain.size(); I != N; ++I) { >> auto *D = Chain[N - I - 1]; >> + if (D == CanonDecl) >> + continue; >> ASTDeclReader::attachPreviousDecl(*this, D, MostRecent, CanonDecl); >> MostRecent = D; >> } >> >> Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=245779&r1=245778&r2=245779&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) >> +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Fri Aug 21 20:47:18 2015 >> @@ -3799,41 +3799,39 @@ void ASTWriter::WriteRedeclarations() { >> SmallVector<serialization::LocalRedeclarationsInfo, 2> >> LocalRedeclsMap; >> for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) { >> - const Decl *Key = Redeclarations[I]; >> - assert((Chain ? Chain->getKeyDeclaration(Key) == Key >> - : Key->isFirstDecl()) && >> - "not the key declaration"); >> + const Decl *FirstLocal = Redeclarations[I]; >> + assert(!FirstLocal->isFromASTFile() && >> + (!FirstLocal->getPreviousDecl() || >> + FirstLocal->getPreviousDecl()->isFromASTFile() || >> + getDeclID(FirstLocal->getPreviousDecl()) < >> NUM_PREDEF_DECL_IDS) && >> + "not the first local declaration"); >> + assert(getDeclID(FirstLocal) >= NUM_PREDEF_DECL_IDS && >> + "should not have predefined decl as first decl"); >> - const Decl *First = Key->getCanonicalDecl(); >> - const Decl *MostRecent = First->getMostRecentDecl(); >> - >> - assert((getDeclID(First) >= NUM_PREDEF_DECL_IDS || First == Key) && >> - "should not have imported key decls for predefined decl"); >> - >> - // If we only have a single declaration, there is no point in storing >> - // a redeclaration chain. >> - if (First == MostRecent) >> - continue; >> - >> unsigned Offset = LocalRedeclChains.size(); >> unsigned Size = 0; >> LocalRedeclChains.push_back(0); // Placeholder for the size. >> // Collect the set of local redeclarations of this declaration, >> from newest >> // to oldest. >> - for (const Decl *Prev = MostRecent; Prev; >> - Prev = Prev->getPreviousDecl()) { >> - if (!Prev->isFromASTFile() && Prev != Key) { >> + for (const Decl *Prev = FirstLocal->getMostRecentDecl(); Prev != >> FirstLocal; >> + Prev = Prev->getPreviousDecl()) { >> + if (!Prev->isFromASTFile()) { >> AddDeclRef(Prev, LocalRedeclChains); >> ++Size; >> } >> } >> + // If we only have a single local declaration, there is no point >> in storing >> + // a redeclaration chain. >> + if (LocalRedeclChains.size() == 1) >> + continue; >> + >> LocalRedeclChains[Offset] = Size; >> // Add the mapping from the first ID from the AST to the set of >> local >> // declarations. >> - LocalRedeclarationsInfo Info = { getDeclID(Key), Offset }; >> + LocalRedeclarationsInfo Info = { getDeclID(FirstLocal), Offset }; >> LocalRedeclsMap.push_back(Info); >> assert(N == Redeclarations.size() && >> @@ -4145,8 +4143,6 @@ void ASTWriter::WriteASTCore(Sema &SemaR >> if (D) { >> assert(D->isCanonicalDecl() && "predefined decl is not >> canonical"); >> DeclIDs[D] = ID; >> - if (D->getMostRecentDecl() != D) >> - Redeclarations.push_back(D); >> } >> }; >> RegisterPredefDecl(Context.getTranslationUnitDecl(), >> @@ -5730,42 +5726,6 @@ void ASTWriter::AddedCXXImplicitMember(c >> DeclUpdates[RD].push_back(DeclUpdate(UPD_CXX_ADDED_IMPLICIT_MEMBER, >> D)); >> } >> -void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl >> *TD, >> - const >> ClassTemplateSpecializationDecl *D) { >> - // The specializations set is kept in the canonical template. >> - TD = TD->getCanonicalDecl(); >> - if (!(!D->isFromASTFile() && TD->isFromASTFile())) >> - return; // Not a source specialization added to a template from PCH. >> - >> - assert(!WritingAST && "Already writing the AST!"); >> - >> DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, >> - D)); >> -} >> - >> -void ASTWriter::AddedCXXTemplateSpecialization( >> - const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { >> - // The specializations set is kept in the canonical template. >> - TD = TD->getCanonicalDecl(); >> - if (!(!D->isFromASTFile() && TD->isFromASTFile())) >> - return; // Not a source specialization added to a template from PCH. >> - >> - assert(!WritingAST && "Already writing the AST!"); >> - >> DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, >> - D)); >> -} >> - >> -void ASTWriter::AddedCXXTemplateSpecialization(const >> FunctionTemplateDecl *TD, >> - const FunctionDecl *D) { >> - // The specializations set is kept in the canonical template. >> - TD = TD->getCanonicalDecl(); >> - if (!(!D->isFromASTFile() && TD->isFromASTFile())) >> - return; // Not a source specialization added to a template from PCH. >> - >> - assert(!WritingAST && "Already writing the AST!"); >> - >> DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, >> - D)); >> -} >> - >> void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) { >> assert(!DoneWritingDeclsAndTypes && "Already done writing updates!"); >> if (!Chain) return; >> >> Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=245779&r1=245778&r2=245779&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) >> +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Fri Aug 21 20:47:18 2015 >> @@ -159,6 +159,19 @@ namespace clang { >> Writer.AddStmt(FD->getBody()); >> } >> + /// Add to the record the first declaration from each module file >> that >> + /// provides a declaration of D. The intent is to provide a >> sufficient >> + /// set such that reloading this set will load all current >> redeclarations. >> + void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) { >> + llvm::MapVector<ModuleFile*, const Decl*> Firsts; >> + // FIXME: We can skip entries that we know are implied by others. >> + for (const Decl *R = D->getMostRecentDecl(); R; R = >> R->getPreviousDecl()) >> + if (IncludeLocal || R->isFromASTFile()) >> + Firsts[Writer.Chain->getOwningModuleFile(R)] = R; >> + for (const auto &F : Firsts) >> + Writer.AddDeclRef(F.second, Record); >> + } >> + >> /// Get the specialization decl from an entry in the specialization >> list. >> template <typename EntryType> >> typename >> RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * >> @@ -194,20 +207,46 @@ namespace clang { >> if (auto *LS = Common->LazySpecializations) >> LazySpecializations = ArrayRef<DeclID>(LS + 1, LS + 1 + LS[0]); >> - Record.push_back(Specializations.size() + >> - PartialSpecializations.size() + >> - LazySpecializations.size()); >> + // Add a slot to the record for the number of specializations. >> + unsigned I = Record.size(); >> + Record.push_back(0); >> + >> for (auto &Entry : Specializations) { >> auto *D = getSpecializationDecl(Entry); >> assert(D->isCanonicalDecl() && "non-canonical decl in set"); >> - Writer.AddDeclRef(D, Record); >> + AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); >> } >> for (auto &Entry : PartialSpecializations) { >> auto *D = getSpecializationDecl(Entry); >> assert(D->isCanonicalDecl() && "non-canonical decl in set"); >> - Writer.AddDeclRef(D, Record); >> + AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); >> } >> Record.append(LazySpecializations.begin(), >> LazySpecializations.end()); >> + >> + // Update the size entry we added earlier. >> + Record[I] = Record.size() - I - 1; >> + } >> + >> + /// Ensure that this template specialization is associated with the >> specified >> + /// template on reload. >> + void RegisterTemplateSpecialization(const Decl *Template, >> + const Decl *Specialization) { >> + Template = Template->getCanonicalDecl(); >> + >> + // If the canonical template is local, we'll write out this >> specialization >> + // when we emit it. >> + // FIXME: We can do the same thing if there is any local >> declaration of >> + // the template, to avoid emitting an update record. >> + if (!Template->isFromASTFile()) >> + return; >> + >> + // We only need to associate the first local declaration of the >> + // specialization. The other declarations will get pulled in by it. >> + if (Writer.getFirstLocalDecl(Specialization) != Specialization) >> + return; >> + >> + Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate( >> + UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization)); >> } >> }; >> } >> @@ -479,6 +518,9 @@ void ASTDeclWriter::VisitFunctionDecl(Fu >> case FunctionDecl::TK_FunctionTemplateSpecialization: { >> FunctionTemplateSpecializationInfo * >> FTSInfo = D->getTemplateSpecializationInfo(); >> + >> + RegisterTemplateSpecialization(FTSInfo->getTemplate(), D); >> + >> Writer.AddDeclRef(FTSInfo->getTemplate(), Record); >> Record.push_back(FTSInfo->getTemplateSpecializationKind()); >> @@ -1249,6 +1291,8 @@ void ASTDeclWriter::VisitClassTemplateDe >> void ASTDeclWriter::VisitClassTemplateSpecializationDecl( >> >> ClassTemplateSpecializationDecl *D) { >> + RegisterTemplateSpecialization(D->getSpecializedTemplate(), D); >> + >> VisitCXXRecordDecl(D); >> llvm::PointerUnion<ClassTemplateDecl *, >> @@ -1308,6 +1352,8 @@ void ASTDeclWriter::VisitVarTemplateDecl >> void ASTDeclWriter::VisitVarTemplateSpecializationDecl( >> VarTemplateSpecializationDecl *D) { >> + RegisterTemplateSpecialization(D->getSpecializedTemplate(), D); >> + >> VisitVarDecl(D); >> llvm::PointerUnion<VarTemplateDecl *, >> VarTemplatePartialSpecializationDecl *> >> @@ -1478,48 +1524,61 @@ void ASTDeclWriter::VisitDeclContext(Dec >> Record.push_back(VisibleOffset); >> } >> -/// Determine whether D is the first declaration in its redeclaration >> chain that >> -/// is not from an AST file. >> -template <typename T> >> -static bool isFirstLocalDecl(Redeclarable<T> *D) { >> - assert(D && !static_cast<T*>(D)->isFromASTFile()); >> - do >> - D = D->getPreviousDecl(); >> - while (D && static_cast<T*>(D)->isFromASTFile()); >> - return !D; >> +/// \brief Is this a local declaration (that is, one that will be >> written to >> +/// our AST file)? This is the case for declarations that are neither >> imported >> +/// from another AST file nor predefined. >> +static bool isLocalDecl(ASTWriter &W, const Decl *D) { >> + if (D->isFromASTFile()) >> + return false; >> + return W.getDeclID(D) >= NUM_PREDEF_DECL_IDS; >> +} >> + >> +const Decl *ASTWriter::getFirstLocalDecl(const Decl *D) { >> + assert(isLocalDecl(*this, D) && "expected a local declaration"); >> + >> + const Decl *Canon = D->getCanonicalDecl(); >> + if (isLocalDecl(*this, Canon)) >> + return Canon; >> + >> + const Decl *&CacheEntry = FirstLocalDeclCache[Canon]; >> + if (CacheEntry) >> + return CacheEntry; >> + >> + for (const Decl *Redecl = D; Redecl; Redecl = >> Redecl->getPreviousDecl()) >> + if (isLocalDecl(*this, Redecl)) >> + D = Redecl; >> + return CacheEntry = D; >> } >> template <typename T> >> void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { >> T *First = D->getFirstDecl(); >> T *MostRecent = First->getMostRecentDecl(); >> + T *DAsT = static_cast<T *>(D); >> if (MostRecent != First) { >> - assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) && >> + assert(isRedeclarableDeclKind(DAsT->getKind()) && >> "Not considered redeclarable?"); >> Writer.AddDeclRef(First, Record); >> - // In a modules build, emit a list of all imported key declarations >> - // (excluding First, if it was imported), so that we can be sure >> that all >> - // redeclarations visible to this module are before D in the redecl >> chain. >> - unsigned I = Record.size(); >> - Record.push_back(0); >> - if (Context.getLangOpts().Modules && Writer.Chain) { >> - if (isFirstLocalDecl(D)) { >> - Writer.Chain->forEachImportedKeyDecl(First, [&](const Decl *D) { >> - if (D != First) >> - Writer.AddDeclRef(D, Record); >> - }); >> - Record[I] = Record.size() - I - 1; >> - >> - // Write a redeclaration chain, attached to the first key decl. >> - >> Writer.Redeclarations.push_back(Writer.Chain->getKeyDeclaration(First)); >> - } >> - } else if (D == First || D->getPreviousDecl()->isFromASTFile()) { >> - assert(isFirstLocalDecl(D) && "imported decl after local decl"); >> - >> - // Write a redeclaration chain attached to the first decl. >> - Writer.Redeclarations.push_back(First); >> + // Write out a list of local redeclarations of this declaration if >> it's the >> + // first local declaration in the chain. >> + const Decl *FirstLocal = Writer.getFirstLocalDecl(DAsT); >> + if (DAsT == FirstLocal) { >> + Writer.Redeclarations.push_back(DAsT); >> + >> + // Emit a list of all imported first declarations so that we can >> be sure >> + // that all redeclarations visible to this module are before D in >> the >> + // redecl chain. >> + unsigned I = Record.size(); >> + Record.push_back(0); >> + if (Writer.Chain) >> + AddFirstDeclFromEachModule(DAsT, /*IncludeLocal*/false); >> + // This is the number of imported first declarations + 1. >> + Record[I] = Record.size() - I; >> + } else { >> + Record.push_back(0); >> + Writer.AddDeclRef(FirstLocal, Record); >> } >> // Make sure that we serialize both the previous and the >> most-recent >> >> Modified: cfe/trunk/test/Modules/cxx-templates.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cxx-templates.cpp?rev=245779&r1=245778&r2=245779&view=diff >> >> ============================================================================== >> --- cfe/trunk/test/Modules/cxx-templates.cpp (original) >> +++ cfe/trunk/test/Modules/cxx-templates.cpp Fri Aug 21 20:47:18 2015 >> @@ -187,10 +187,10 @@ namespace Std { >> // CHECK-DUMP: ClassTemplateDecl {{.*}} >> <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in >> cxx_templates_common SomeTemplate >> // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev >> {{.*}} SomeTemplate >> -// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' >> -// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} >> SomeTemplate definition >> -// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' >> -// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} >> SomeTemplate >> // CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' >> // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} >> SomeTemplate definition >> // CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' >> +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} >> SomeTemplate >> +// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' >> +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} >> SomeTemplate definition >> +// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' >> >> >> _______________________________________________ >> 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