r245779 - [modules] Rearrange how redeclaration chains are loaded, to remove a walk over
Justin Bogner via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 27 10:47:30 PDT 2015
Richard Smith via cfe-commits <cfe-commits at lists.llvm.org> writes:
> 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.
It looks like ASTDeclWriter::AddFirstDeclFromEachModule is called with a
null `this` since this change, which has been causing ubsan failures on
76 tests since it went in:
ASTWriterDecl.cpp:170:18: runtime error: member call on null pointer of type 'clang::ASTReader'
Logs and other failures here:
http://lab.llvm.org:8080/green/job/clang-stage2-cmake-RgSan_check/146/
I guess you must've missed the failure email. Could you please take a
look?
> 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%.
>
> 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 at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list