https://github.com/ChuanqiXu9 updated https://github.com/llvm/llvm-project/pull/83108
>From 59e1880df74434e3c446705788d92b5949d99536 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev <v.g.vassi...@gmail.com> Date: Sun, 7 Jan 2018 15:16:11 +0200 Subject: [PATCH 1/3] D41416: [modules] [pch] Do not deserialize all lazy template specializations when looking for one. --- clang/include/clang/AST/DeclTemplate.h | 36 ++++++++- clang/lib/AST/DeclTemplate.cpp | 96 +++++++++++++++++------ clang/lib/AST/ODRHash.cpp | 15 ++++ clang/lib/Serialization/ASTReader.cpp | 25 ++++-- clang/lib/Serialization/ASTReaderDecl.cpp | 36 ++++++--- clang/lib/Serialization/ASTWriter.cpp | 21 ++++- clang/lib/Serialization/ASTWriterDecl.cpp | 74 ++++++++++++++--- 7 files changed, 242 insertions(+), 61 deletions(-) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index e3b6a7efb1127a..4ed9b58d4ff609 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -256,6 +256,9 @@ class TemplateArgumentList final TemplateArgumentList(const TemplateArgumentList &) = delete; TemplateArgumentList &operator=(const TemplateArgumentList &) = delete; + /// Create hash for the given arguments. + static unsigned ComputeODRHash(ArrayRef<TemplateArgument> Args); + /// Create a new template argument list that copies the given set of /// template arguments. static TemplateArgumentList *CreateCopy(ASTContext &Context, @@ -730,6 +733,26 @@ class RedeclarableTemplateDecl : public TemplateDecl, } void anchor() override; + struct LazySpecializationInfo { + uint32_t DeclID = ~0U; + unsigned ODRHash = ~0U; + bool IsPartial = false; + LazySpecializationInfo(uint32_t ID, unsigned Hash = ~0U, + bool Partial = false) + : DeclID(ID), ODRHash(Hash), IsPartial(Partial) { } + LazySpecializationInfo() { } + bool operator<(const LazySpecializationInfo &Other) const { + return DeclID < Other.DeclID; + } + bool operator==(const LazySpecializationInfo &Other) const { + assert((DeclID != Other.DeclID || ODRHash == Other.ODRHash) && + "Hashes differ!"); + assert((DeclID != Other.DeclID || IsPartial == Other.IsPartial) && + "Both must be the same kinds!"); + return DeclID == Other.DeclID; + } + }; + protected: template <typename EntryType> struct SpecEntryTraits { using DeclType = EntryType; @@ -770,7 +793,12 @@ class RedeclarableTemplateDecl : public TemplateDecl, return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin()); } - void loadLazySpecializationsImpl() const; + void loadLazySpecializationsImpl(bool OnlyPartial = false) const; + + void loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args, + TemplateParameterList *TPL = nullptr) const; + + Decl *loadLazySpecializationImpl(LazySpecializationInfo &LazySpecInfo) const; template <class EntryType, typename ...ProfileArguments> typename SpecEntryTraits<EntryType>::DeclType* @@ -797,7 +825,7 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// /// The first value in the array is the number of specializations/partial /// specializations that follow. - uint32_t *LazySpecializations = nullptr; + LazySpecializationInfo *LazySpecializations = nullptr; /// The set of "injected" template arguments used within this /// template. @@ -2268,7 +2296,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { friend class TemplateDeclInstantiator; /// Load any lazily-loaded specializations from the external source. - void LoadLazySpecializations() const; + void LoadLazySpecializations(bool OnlyPartial = false) const; /// Get the underlying class declarations of the template. CXXRecordDecl *getTemplatedDecl() const { @@ -3039,7 +3067,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl { friend class ASTDeclWriter; /// Load any lazily-loaded specializations from the external source. - void LoadLazySpecializations() const; + void LoadLazySpecializations(bool OnlyPartial = false) const; /// Get the underlying variable declarations of the template. VarDecl *getTemplatedDecl() const { diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 3c217d6a6a5ae3..1babe39ee2a7e5 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -20,6 +20,8 @@ #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" +#include "clang/AST/ODRHash.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LLVM.h" @@ -331,16 +333,43 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c return Common; } -void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { +void RedeclarableTemplateDecl::loadLazySpecializationsImpl( + bool OnlyPartial/*=false*/) const { // Grab the most recent declaration to ensure we've loaded any lazy // redeclarations of this template. CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); - if (CommonBasePtr->LazySpecializations) { - ASTContext &Context = getASTContext(); - uint32_t *Specs = CommonBasePtr->LazySpecializations; - CommonBasePtr->LazySpecializations = nullptr; - for (uint32_t I = 0, N = *Specs++; I != N; ++I) - (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + if (auto *Specs = CommonBasePtr->LazySpecializations) { + if (!OnlyPartial) + CommonBasePtr->LazySpecializations = nullptr; + for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I) { + // Skip over already loaded specializations. + if (!Specs[I+1].ODRHash) + continue; + if (!OnlyPartial || Specs[I+1].IsPartial) + (void)loadLazySpecializationImpl(Specs[I+1]); + } + } +} + +Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl( + LazySpecializationInfo &LazySpecInfo) const { + uint32_t ID = LazySpecInfo.DeclID; + assert(ID && "Loading already loaded specialization!"); + // Note that we loaded the specialization. + LazySpecInfo.DeclID = LazySpecInfo.ODRHash = LazySpecInfo.IsPartial = 0; + return getASTContext().getExternalSource()->GetExternalDecl(ID); +} + +void +RedeclarableTemplateDecl::loadLazySpecializationsImpl(ArrayRef<TemplateArgument> + Args, + TemplateParameterList *TPL) const { + CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); + if (auto *Specs = CommonBasePtr->LazySpecializations) { + unsigned Hash = TemplateArgumentList::ComputeODRHash(Args); + for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I) + if (Specs[I+1].ODRHash && Specs[I+1].ODRHash == Hash) + (void)loadLazySpecializationImpl(Specs[I+1]); } } @@ -351,6 +380,8 @@ RedeclarableTemplateDecl::findSpecializationImpl( ProfileArguments&&... ProfileArgs) { using SETraits = SpecEntryTraits<EntryType>; + loadLazySpecializationsImpl(std::forward<ProfileArguments>(ProfileArgs)...); + llvm::FoldingSetNodeID ID; EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)..., getASTContext()); @@ -366,10 +397,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl( if (InsertPos) { #ifndef NDEBUG + auto Args = SETraits::getTemplateArgs(Entry); + // Due to hash collisions, it can happen that we load another template + // specialization with the same hash. This is fine, as long as the next + // call to findSpecializationImpl does not find a matching Decl for the + // template arguments. + loadLazySpecializationsImpl(Args); void *CorrectInsertPos; - assert(!findSpecializationImpl(Specializations, - CorrectInsertPos, - SETraits::getTemplateArgs(Entry)) && + assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) && InsertPos == CorrectInsertPos && "given incorrect InsertPos for specialization"); #endif @@ -443,12 +478,14 @@ FunctionTemplateDecl::getSpecializations() const { FunctionDecl * FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + auto *Common = getCommonPtr(); + return findSpecializationImpl(Common->Specializations, InsertPos, Args); } void FunctionTemplateDecl::addSpecialization( FunctionTemplateSpecializationInfo *Info, void *InsertPos) { - addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info, + auto *Common = getCommonPtr(); + addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info, InsertPos); } @@ -508,8 +545,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, DeclarationName(), nullptr, nullptr); } -void ClassTemplateDecl::LoadLazySpecializations() const { - loadLazySpecializationsImpl(); +void ClassTemplateDecl::LoadLazySpecializations( + bool OnlyPartial/*=false*/) const { + loadLazySpecializationsImpl(OnlyPartial); } llvm::FoldingSetVector<ClassTemplateSpecializationDecl> & @@ -520,7 +558,7 @@ ClassTemplateDecl::getSpecializations() const { llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> & ClassTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(); + LoadLazySpecializations(/*PartialOnly = */ true); return getCommonPtr()->PartialSpecializations; } @@ -534,12 +572,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const { ClassTemplateSpecializationDecl * ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + auto *Common = getCommonPtr(); + return findSpecializationImpl(Common->Specializations, InsertPos, Args); } void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos) { - addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos); + auto *Common = getCommonPtr(); + addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D, + InsertPos); } ClassTemplatePartialSpecializationDecl * @@ -883,6 +924,14 @@ TemplateArgumentList::CreateCopy(ASTContext &Context, return new (Mem) TemplateArgumentList(Args); } +unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) { + ODRHash Hasher; + for (TemplateArgument TA : Args) + Hasher.AddTemplateArgument(TA); + + return Hasher.CalculateHash(); +} + FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create( ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template, TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs, @@ -1225,8 +1274,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, DeclarationName(), nullptr, nullptr); } -void VarTemplateDecl::LoadLazySpecializations() const { - loadLazySpecializationsImpl(); +void VarTemplateDecl::LoadLazySpecializations( + bool OnlyPartial/*=false*/) const { + loadLazySpecializationsImpl(OnlyPartial); } llvm::FoldingSetVector<VarTemplateSpecializationDecl> & @@ -1237,7 +1287,7 @@ VarTemplateDecl::getSpecializations() const { llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> & VarTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(); + LoadLazySpecializations(/*PartialOnly = */ true); return getCommonPtr()->PartialSpecializations; } @@ -1251,12 +1301,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const { VarTemplateSpecializationDecl * VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + auto *Common = getCommonPtr(); + return findSpecializationImpl(Common->Specializations, InsertPos, Args); } void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos) { - addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos); + auto *Common = getCommonPtr(); + addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos); } VarTemplatePartialSpecializationDecl * diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 2dbc259138a897..ffc48ee7cb95ac 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -812,6 +812,21 @@ void ODRHash::AddDecl(const Decl *D) { for (const TemplateArgument &TA : List.asArray()) AddTemplateArgument(TA); } + + // If this was a specialization we should take into account its template + // arguments. This helps to reduce collisions coming when visiting template + // specialization types (eg. when processing type template arguments). + ArrayRef<TemplateArgument> Args; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->getTemplateSpecializationArgs()) + Args = FD->getTemplateSpecializationArgs()->asArray(); + + for (auto &TA : Args) + AddTemplateArgument(TA); } namespace { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 683a076e6bc399..3a4fcc8c118fee 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7549,14 +7549,23 @@ void ASTReader::CompleteRedeclChain(const Decl *D) { } } - if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) - CTSD->getSpecializedTemplate()->LoadLazySpecializations(); - if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) - VTSD->getSpecializedTemplate()->LoadLazySpecializations(); - if (auto *FD = dyn_cast<FunctionDecl>(D)) { - if (auto *Template = FD->getPrimaryTemplate()) - Template->LoadLazySpecializations(); - } + RedeclarableTemplateDecl *Template = nullptr; + ArrayRef<TemplateArgument> Args; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + Template = CTSD->getSpecializedTemplate(); + Args = CTSD->getTemplateArgs().asArray(); + } else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) { + Template = VTSD->getSpecializedTemplate(); + Args = VTSD->getTemplateArgs().asArray(); + } else if (auto *FD = dyn_cast<FunctionDecl>(D)) { + if (auto *Tmplt = FD->getPrimaryTemplate()) { + Template = Tmplt; + Args = FD->getTemplateSpecializationArgs()->asArray(); + } + } + + if (Template) + Template->loadLazySpecializationsImpl(Args); } CXXCtorInitializer ** diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index ffba04f28782ea..07d4fe81957d7c 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -88,6 +88,8 @@ namespace clang { const SourceLocation ThisDeclLoc; using RecordData = ASTReader::RecordData; + using LazySpecializationInfo + = RedeclarableTemplateDecl::LazySpecializationInfo; TypeID DeferredTypeID = 0; unsigned AnonymousDeclNumber = 0; @@ -134,9 +136,16 @@ namespace clang { return Record.readString(); } - void readDeclIDList(SmallVectorImpl<DeclID> &IDs) { + LazySpecializationInfo ReadLazySpecializationInfo() { + DeclID ID = readDeclID(); + unsigned Hash = Record.readInt(); + bool IsPartial = Record.readInt(); + return LazySpecializationInfo(ID, Hash, IsPartial); + } + + void readDeclIDList(SmallVectorImpl<LazySpecializationInfo> &IDs) { for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I) - IDs.push_back(readDeclID()); + IDs.push_back(ReadLazySpecializationInfo()); } Decl *readDecl() { @@ -267,7 +276,7 @@ namespace clang { template <typename T> static void AddLazySpecializations(T *D, - SmallVectorImpl<serialization::DeclID>& IDs) { + SmallVectorImpl<LazySpecializationInfo>& IDs) { if (IDs.empty()) return; @@ -277,12 +286,11 @@ namespace clang { auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations; if (auto &Old = LazySpecializations) { - IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); + IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].DeclID); llvm::sort(IDs); IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); } - - auto *Result = new (C) serialization::DeclID[1 + IDs.size()]; + auto *Result = new (C) LazySpecializationInfo[1 + IDs.size()]; *Result = IDs.size(); std::copy(IDs.begin(), IDs.end(), Result + 1); @@ -320,7 +328,7 @@ namespace clang { void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D, SmallVectorImpl<serialization::DeclID> &); + void UpdateDecl(Decl *D, llvm::SmallVectorImpl<LazySpecializationInfo>&); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -2450,7 +2458,7 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. - SmallVector<serialization::DeclID, 32> SpecIDs; + SmallVector<LazySpecializationInfo, 32> SpecIDs; readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -2478,7 +2486,7 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This VarTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. - SmallVector<serialization::DeclID, 32> SpecIDs; + SmallVector<LazySpecializationInfo, 32> SpecIDs; readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -2580,7 +2588,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This FunctionTemplateDecl owns a CommonPtr; read it. - SmallVector<serialization::DeclID, 32> SpecIDs; + SmallVector<LazySpecializationInfo, 32> SpecIDs; readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -4191,7 +4199,9 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); - SmallVector<serialization::DeclID, 8> PendingLazySpecializationIDs; + using LazySpecializationInfo + = RedeclarableTemplateDecl::LazySpecializationInfo; + llvm::SmallVector<LazySpecializationInfo, 8> PendingLazySpecializationIDs; if (UpdI != DeclUpdateOffsets.end()) { auto UpdateOffsets = std::move(UpdI->second); @@ -4461,7 +4471,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { } void ASTDeclReader::UpdateDecl(Decl *D, - llvm::SmallVectorImpl<serialization::DeclID> &PendingLazySpecializationIDs) { + SmallVectorImpl<LazySpecializationInfo> &PendingLazySpecializationIDs) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { @@ -4474,7 +4484,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: // It will be added to the template's lazy specialization set. - PendingLazySpecializationIDs.push_back(readDeclID()); + PendingLazySpecializationIDs.push_back(ReadLazySpecializationInfo()); break; case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 740bec586a5e33..6cb6d3d8fae4d8 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5329,12 +5329,29 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { switch (Kind) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: - case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: assert(Update.getDecl() && "no decl to add?"); Record.push_back(GetDeclRef(Update.getDecl())); break; - + case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: { + const Decl *Spec = Update.getDecl(); + assert(Spec && "no decl to add?"); + Record.push_back(GetDeclRef(Spec)); + ArrayRef<TemplateArgument> Args; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Spec)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Spec)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast<FunctionDecl>(Spec)) + Args = FD->getTemplateSpecializationArgs()->asArray(); + assert(Args.size()); + Record.push_back(TemplateArgumentList::ComputeODRHash(Args)); + bool IsPartialSpecialization + = isa<ClassTemplatePartialSpecializationDecl>(Spec) || + isa<VarTemplatePartialSpecializationDecl>(Spec); + Record.push_back(IsPartialSpecialization); + break; + } case UPD_CXX_ADDED_FUNCTION_DEFINITION: case UPD_CXX_ADDED_VAR_DEFINITION: break; diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index f224075643e998..2cbf8e7a82fb04 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -175,11 +175,11 @@ namespace clang { Record.AddSourceLocation(typeParams->getRAngleLoc()); } - /// 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; + /// Collect the first declaration from each module file that provides a + /// declaration of D. + void CollectFirstDeclFromEachModule(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 (R->isFromASTFile()) @@ -187,10 +187,49 @@ namespace clang { else if (IncludeLocal) Firsts[nullptr] = R; } + } + + /// 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; + CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); + for (const auto &F : Firsts) Record.AddDeclRef(F.second); } + /// Add to the record the first template specialization from each module + /// file that provides a declaration of D. We store the DeclId and an + /// ODRHash of the template arguments of D which should provide enough + /// information to load D only if the template instantiator needs it. + void AddFirstSpecializationDeclFromEachModule(const Decl *D, + bool IncludeLocal) { + assert(isa<ClassTemplateSpecializationDecl>(D) || + isa<VarTemplateSpecializationDecl>(D) || isa<FunctionDecl>(D) && + "Must not be called with other decls"); + llvm::MapVector<ModuleFile*, const Decl*> Firsts; + CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); + + for (const auto &F : Firsts) { + Record.AddDeclRef(F.second); + ArrayRef<TemplateArgument> Args; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast<FunctionDecl>(D)) + Args = FD->getTemplateSpecializationArgs()->asArray(); + assert(Args.size()); + Record.push_back(TemplateArgumentList::ComputeODRHash(Args)); + bool IsPartialSpecialization + = isa<ClassTemplatePartialSpecializationDecl>(D) || + isa<VarTemplatePartialSpecializationDecl>(D); + Record.push_back(IsPartialSpecialization); + } + } + /// Get the specialization decl from an entry in the specialization list. template <typename EntryType> typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * @@ -203,7 +242,8 @@ namespace clang { decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) { return Common->PartialSpecializations; } - ArrayRef<Decl> getPartialSpecializations(FunctionTemplateDecl::Common *) { + MutableArrayRef<FunctionTemplateSpecializationInfo> + getPartialSpecializations(FunctionTemplateDecl::Common *) { return std::nullopt; } @@ -220,9 +260,11 @@ namespace clang { assert(!Common->LazySpecializations); } - ArrayRef<DeclID> LazySpecializations; + using LazySpecializationInfo + = RedeclarableTemplateDecl::LazySpecializationInfo; + ArrayRef<LazySpecializationInfo> LazySpecializations; if (auto *LS = Common->LazySpecializations) - LazySpecializations = llvm::ArrayRef(LS + 1, LS[0]); + LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].DeclID); // Add a slot to the record for the number of specializations. unsigned I = Record.size(); @@ -238,12 +280,20 @@ namespace clang { for (auto *D : Specs) { assert(D->isCanonicalDecl() && "non-canonical decl in set"); - AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); + AddFirstSpecializationDeclFromEachModule(D, /*IncludeLocal*/true); + } + for (auto &SpecInfo : LazySpecializations) { + Record.push_back(SpecInfo.DeclID); + Record.push_back(SpecInfo.ODRHash); + Record.push_back(SpecInfo.IsPartial); } - Record.append(LazySpecializations.begin(), LazySpecializations.end()); - // Update the size entry we added earlier. - Record[I] = Record.size() - I - 1; + // Update the size entry we added earlier. We linerized the + // LazySpecializationInfo members and we need to adjust the size as we + // will read them always together. + assert ((Record.size() - I - 1) % 3 == 0 + && "Must be divisible by LazySpecializationInfo count!"); + Record[I] = (Record.size() - I - 1) / 3; } /// Ensure that this template specialization is associated with the specified >From 855abec633f8e394df1a21f252dc37fddcdd2096 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Tue, 27 Feb 2024 15:45:40 +0800 Subject: [PATCH 2/3] Fix test mismatch failure --- clang/test/Modules/cxx-templates.cpp | 9 +++++---- clang/test/Modules/odr_hash.cpp | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index b7d5741e69af61..2d285c10ceec59 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -251,7 +251,7 @@ 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-NEXT: TemplateArgument type 'char[1]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition // CHECK-DUMP-NEXT: DefinitionData // CHECK-DUMP-NEXT: DefaultConstructor @@ -260,9 +260,9 @@ namespace Std { // CHECK-DUMP-NEXT: CopyAssignment // CHECK-DUMP-NEXT: MoveAssignment // CHECK-DUMP-NEXT: Destructor -// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]' -// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate // 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: DefinitionData // CHECK-DUMP-NEXT: DefaultConstructor @@ -271,4 +271,5 @@ namespace Std { // CHECK-DUMP-NEXT: CopyAssignment // CHECK-DUMP-NEXT: MoveAssignment // CHECK-DUMP-NEXT: Destructor -// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]' +// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]' + diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index fa8b2c81ab46e1..7cea3af3f41bdd 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -3084,8 +3084,8 @@ struct S5 { }; #else S5 s5; -// expected-error@second.h:* {{'PointersAndReferences::S5::x' from module 'SecondModule' is not present in definition of 'PointersAndReferences::S5' in module 'FirstModule'}} -// expected-note@first.h:* {{declaration of 'x' does not match}} +// expected-error@first.h:* {{'PointersAndReferences::S5::x' from module 'FirstModule' is not present in definition of 'PointersAndReferences::S5' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'x' does not match}} #endif #if defined(FIRST) >From 244e7457e1568a5e3565d7a5f30e7d8ae5694cdb Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Tue, 27 Feb 2024 15:46:39 +0800 Subject: [PATCH 3/3] fmt --- clang/include/clang/AST/DeclTemplate.h | 4 ++-- clang/lib/AST/DeclTemplate.cpp | 28 ++++++++++------------ clang/lib/Serialization/ASTReaderDecl.cpp | 21 ++++++++-------- clang/lib/Serialization/ASTWriter.cpp | 6 ++--- clang/lib/Serialization/ASTWriterDecl.cpp | 29 ++++++++++++----------- 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 4ed9b58d4ff609..51caef54baac26 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -739,8 +739,8 @@ class RedeclarableTemplateDecl : public TemplateDecl, bool IsPartial = false; LazySpecializationInfo(uint32_t ID, unsigned Hash = ~0U, bool Partial = false) - : DeclID(ID), ODRHash(Hash), IsPartial(Partial) { } - LazySpecializationInfo() { } + : DeclID(ID), ODRHash(Hash), IsPartial(Partial) {} + LazySpecializationInfo() {} bool operator<(const LazySpecializationInfo &Other) const { return DeclID < Other.DeclID; } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 1babe39ee2a7e5..aa2368783df7b5 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -16,12 +16,12 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/ODRHash.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" -#include "clang/AST/ODRHash.h" -#include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LLVM.h" @@ -334,7 +334,7 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c } void RedeclarableTemplateDecl::loadLazySpecializationsImpl( - bool OnlyPartial/*=false*/) const { + bool OnlyPartial /*=false*/) const { // Grab the most recent declaration to ensure we've loaded any lazy // redeclarations of this template. CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); @@ -343,16 +343,16 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl( CommonBasePtr->LazySpecializations = nullptr; for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I) { // Skip over already loaded specializations. - if (!Specs[I+1].ODRHash) + if (!Specs[I + 1].ODRHash) continue; - if (!OnlyPartial || Specs[I+1].IsPartial) - (void)loadLazySpecializationImpl(Specs[I+1]); + if (!OnlyPartial || Specs[I + 1].IsPartial) + (void)loadLazySpecializationImpl(Specs[I + 1]); } } } Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl( - LazySpecializationInfo &LazySpecInfo) const { + LazySpecializationInfo &LazySpecInfo) const { uint32_t ID = LazySpecInfo.DeclID; assert(ID && "Loading already loaded specialization!"); // Note that we loaded the specialization. @@ -360,16 +360,14 @@ Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl( return getASTContext().getExternalSource()->GetExternalDecl(ID); } -void -RedeclarableTemplateDecl::loadLazySpecializationsImpl(ArrayRef<TemplateArgument> - Args, - TemplateParameterList *TPL) const { +void RedeclarableTemplateDecl::loadLazySpecializationsImpl( + ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const { CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); if (auto *Specs = CommonBasePtr->LazySpecializations) { unsigned Hash = TemplateArgumentList::ComputeODRHash(Args); for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I) - if (Specs[I+1].ODRHash && Specs[I+1].ODRHash == Hash) - (void)loadLazySpecializationImpl(Specs[I+1]); + if (Specs[I + 1].ODRHash && Specs[I + 1].ODRHash == Hash) + (void)loadLazySpecializationImpl(Specs[I + 1]); } } @@ -546,7 +544,7 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, } void ClassTemplateDecl::LoadLazySpecializations( - bool OnlyPartial/*=false*/) const { + bool OnlyPartial /*=false*/) const { loadLazySpecializationsImpl(OnlyPartial); } @@ -1275,7 +1273,7 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, } void VarTemplateDecl::LoadLazySpecializations( - bool OnlyPartial/*=false*/) const { + bool OnlyPartial /*=false*/) const { loadLazySpecializationsImpl(OnlyPartial); } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 07d4fe81957d7c..95942387a9e18e 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -88,8 +88,8 @@ namespace clang { const SourceLocation ThisDeclLoc; using RecordData = ASTReader::RecordData; - using LazySpecializationInfo - = RedeclarableTemplateDecl::LazySpecializationInfo; + using LazySpecializationInfo = + RedeclarableTemplateDecl::LazySpecializationInfo; TypeID DeferredTypeID = 0; unsigned AnonymousDeclNumber = 0; @@ -274,9 +274,9 @@ namespace clang { : Reader(Reader), Record(Record), Loc(Loc), ThisDeclID(thisDeclID), ThisDeclLoc(ThisDeclLoc) {} - template <typename T> static - void AddLazySpecializations(T *D, - SmallVectorImpl<LazySpecializationInfo>& IDs) { + template <typename T> + static void + AddLazySpecializations(T *D, SmallVectorImpl<LazySpecializationInfo> &IDs) { if (IDs.empty()) return; @@ -328,7 +328,7 @@ namespace clang { void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D, llvm::SmallVectorImpl<LazySpecializationInfo>&); + void UpdateDecl(Decl *D, llvm::SmallVectorImpl<LazySpecializationInfo> &); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -4199,8 +4199,8 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); - using LazySpecializationInfo - = RedeclarableTemplateDecl::LazySpecializationInfo; + using LazySpecializationInfo = + RedeclarableTemplateDecl::LazySpecializationInfo; llvm::SmallVector<LazySpecializationInfo, 8> PendingLazySpecializationIDs; if (UpdI != DeclUpdateOffsets.end()) { @@ -4470,8 +4470,9 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { } } -void ASTDeclReader::UpdateDecl(Decl *D, - SmallVectorImpl<LazySpecializationInfo> &PendingLazySpecializationIDs) { +void ASTDeclReader::UpdateDecl( + Decl *D, + SmallVectorImpl<LazySpecializationInfo> &PendingLazySpecializationIDs) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 6cb6d3d8fae4d8..30deca374afd2e 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5346,9 +5346,9 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { Args = FD->getTemplateSpecializationArgs()->asArray(); assert(Args.size()); Record.push_back(TemplateArgumentList::ComputeODRHash(Args)); - bool IsPartialSpecialization - = isa<ClassTemplatePartialSpecializationDecl>(Spec) || - isa<VarTemplatePartialSpecializationDecl>(Spec); + bool IsPartialSpecialization = + isa<ClassTemplatePartialSpecializationDecl>(Spec) || + isa<VarTemplatePartialSpecializationDecl>(Spec); Record.push_back(IsPartialSpecialization); break; } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 2cbf8e7a82fb04..95d8735fe5acf7 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -177,8 +177,9 @@ namespace clang { /// Collect the first declaration from each module file that provides a /// declaration of D. - void CollectFirstDeclFromEachModule(const Decl *D, bool IncludeLocal, - llvm::MapVector<ModuleFile*, const Decl*> &Firsts) { + void CollectFirstDeclFromEachModule( + 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()) { @@ -193,7 +194,7 @@ namespace clang { /// 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; + llvm::MapVector<ModuleFile *, const Decl *> Firsts; CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); for (const auto &F : Firsts) @@ -207,9 +208,9 @@ namespace clang { void AddFirstSpecializationDeclFromEachModule(const Decl *D, bool IncludeLocal) { assert(isa<ClassTemplateSpecializationDecl>(D) || - isa<VarTemplateSpecializationDecl>(D) || isa<FunctionDecl>(D) && - "Must not be called with other decls"); - llvm::MapVector<ModuleFile*, const Decl*> Firsts; + isa<VarTemplateSpecializationDecl>(D) || + isa<FunctionDecl>(D) && "Must not be called with other decls"); + llvm::MapVector<ModuleFile *, const Decl *> Firsts; CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); for (const auto &F : Firsts) { @@ -223,9 +224,9 @@ namespace clang { Args = FD->getTemplateSpecializationArgs()->asArray(); assert(Args.size()); Record.push_back(TemplateArgumentList::ComputeODRHash(Args)); - bool IsPartialSpecialization - = isa<ClassTemplatePartialSpecializationDecl>(D) || - isa<VarTemplatePartialSpecializationDecl>(D); + bool IsPartialSpecialization = + isa<ClassTemplatePartialSpecializationDecl>(D) || + isa<VarTemplatePartialSpecializationDecl>(D); Record.push_back(IsPartialSpecialization); } } @@ -260,8 +261,8 @@ namespace clang { assert(!Common->LazySpecializations); } - using LazySpecializationInfo - = RedeclarableTemplateDecl::LazySpecializationInfo; + using LazySpecializationInfo = + RedeclarableTemplateDecl::LazySpecializationInfo; ArrayRef<LazySpecializationInfo> LazySpecializations; if (auto *LS = Common->LazySpecializations) LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].DeclID); @@ -280,7 +281,7 @@ namespace clang { for (auto *D : Specs) { assert(D->isCanonicalDecl() && "non-canonical decl in set"); - AddFirstSpecializationDeclFromEachModule(D, /*IncludeLocal*/true); + AddFirstSpecializationDeclFromEachModule(D, /*IncludeLocal*/ true); } for (auto &SpecInfo : LazySpecializations) { Record.push_back(SpecInfo.DeclID); @@ -291,8 +292,8 @@ namespace clang { // Update the size entry we added earlier. We linerized the // LazySpecializationInfo members and we need to adjust the size as we // will read them always together. - assert ((Record.size() - I - 1) % 3 == 0 - && "Must be divisible by LazySpecializationInfo count!"); + assert((Record.size() - I - 1) % 3 == 0 && + "Must be divisible by LazySpecializationInfo count!"); Record[I] = (Record.size() - I - 1) / 3; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits