r245779 - [modules] Rearrange how redeclaration chains are loaded, to remove a walk over
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 27 14:41:38 PDT 2015
On Sat, Aug 22, 2015 at 1:16 AM, Vassil Vassilev <vvasilev at 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 at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150827/1003a122/attachment-0001.html>
More information about the cfe-commits
mailing list