From 2a0bc6aed03085fdd71983ba51b270a10005274f Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Tue, 5 Mar 2024 12:01:03 +0000 Subject: [PATCH 1/5] TraverseDecl might deserialize --- core/dictgen/src/Scanner.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/dictgen/src/Scanner.cxx b/core/dictgen/src/Scanner.cxx index 692f9cd91ad33..36e0a75802b31 100644 --- a/core/dictgen/src/Scanner.cxx +++ b/core/dictgen/src/Scanner.cxx @@ -58,8 +58,6 @@ inline static bool IsElementPresent(const std::vector &v, T *el){ using namespace ROOT; using namespace clang; -extern cling::Interpreter *gInterp; - const char* RScanner::fgClangDeclKey = "ClangDecl"; // property key used for connection with Clang objects const char* RScanner::fgClangFuncKey = "ClangFunc"; // property key for demangled names @@ -1059,6 +1057,8 @@ void RScanner::Scan(const clang::ASTContext &C) std::cout<<"File name detected"<(&fInterpreter)); + if (fScanType == EScanType::kTwoPasses) TraverseDecl(C.getTranslationUnitDecl()); From a4b745088e70b0289199539d94138d240f080ba5 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Fri, 13 Dec 2024 17:00:56 +0100 Subject: [PATCH 2/5] [llvm-project] Revert our version of D41416 --- .../clang/include/clang/AST/DeclTemplate.h | 36 +------ .../clang/lib/AST/DeclTemplate.cpp | 96 +++++-------------- .../llvm-project/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, 61 insertions(+), 242 deletions(-) diff --git a/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h b/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h index 26428aaecc7eb..04832a91d6fa8 100644 --- a/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h +++ b/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h @@ -267,9 +267,6 @@ class TemplateArgumentList final static TemplateArgumentList *CreateCopy(ASTContext &Context, ArrayRef Args); - /// \brief Create hash for the given arguments. - static unsigned ComputeODRHash(ArrayRef Args); - /// Construct a new, temporary template argument list on the stack. /// /// The template argument list does not own the template arguments @@ -752,26 +749,6 @@ 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 struct SpecEntryTraits { using DeclType = EntryType; @@ -812,12 +789,7 @@ class RedeclarableTemplateDecl : public TemplateDecl, return SpecIterator(isEnd ? Specs.end() : Specs.begin()); } - void loadLazySpecializationsImpl(bool OnlyPartial = false) const; - - void loadLazySpecializationsImpl(llvm::ArrayRef Args, - TemplateParameterList *TPL = nullptr) const; - - Decl *loadLazySpecializationImpl(LazySpecializationInfo &LazySpecInfo) const; + void loadLazySpecializationsImpl() const; template typename SpecEntryTraits::DeclType* @@ -844,7 +816,7 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// /// The first value in the array is the number of specializations/partial /// specializations that follow. - LazySpecializationInfo *LazySpecializations = nullptr; + uint32_t *LazySpecializations = nullptr; /// The set of "injected" template arguments used within this /// template. @@ -2329,7 +2301,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { friend class TemplateDeclInstantiator; /// Load any lazily-loaded specializations from the external source. - void LoadLazySpecializations(bool OnlyPartial = false) const; + void LoadLazySpecializations() const; /// Get the underlying class declarations of the template. CXXRecordDecl *getTemplatedDecl() const { @@ -3114,7 +3086,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl { friend class ASTDeclWriter; /// Load any lazily-loaded specializations from the external source. - void LoadLazySpecializations(bool OnlyPartial = false) const; + void LoadLazySpecializations() const; /// Get the underlying variable declarations of the template. VarDecl *getTemplatedDecl() const { diff --git a/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp b/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp index 8380b44ed377e..7d7556e670f95 100644 --- a/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp +++ b/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp @@ -20,8 +20,6 @@ #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" @@ -333,43 +331,16 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c return Common; } -void RedeclarableTemplateDecl::loadLazySpecializationsImpl( - bool OnlyPartial/*=false*/) const { +void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { // Grab the most recent declaration to ensure we've loaded any lazy // redeclarations of this template. CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); - 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 - 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 (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]); } } @@ -380,8 +351,6 @@ RedeclarableTemplateDecl::findSpecializationImpl( ProfileArguments&&... ProfileArgs) { using SETraits = SpecEntryTraits; - loadLazySpecializationsImpl(std::forward(ProfileArgs)...); - llvm::FoldingSetNodeID ID; EntryType::Profile(ID, std::forward(ProfileArgs)..., getASTContext()); @@ -397,14 +366,10 @@ 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, Args) && + assert(!findSpecializationImpl(Specializations, + CorrectInsertPos, + SETraits::getTemplateArgs(Entry)) && InsertPos == CorrectInsertPos && "given incorrect InsertPos for specialization"); #endif @@ -478,14 +443,12 @@ FunctionTemplateDecl::getSpecializations() const { FunctionDecl * FunctionTemplateDecl::findSpecialization(ArrayRef Args, void *&InsertPos) { - auto *Common = getCommonPtr(); - return findSpecializationImpl(Common->Specializations, InsertPos, Args); + return findSpecializationImpl(getSpecializations(), InsertPos, Args); } void FunctionTemplateDecl::addSpecialization( FunctionTemplateSpecializationInfo *Info, void *InsertPos) { - auto *Common = getCommonPtr(); - addSpecializationImpl(Common->Specializations, Info, + addSpecializationImpl(getSpecializations(), Info, InsertPos); } @@ -545,9 +508,8 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, DeclarationName(), nullptr, nullptr); } -void ClassTemplateDecl::LoadLazySpecializations( - bool OnlyPartial/*=false*/) const { - loadLazySpecializationsImpl(OnlyPartial); +void ClassTemplateDecl::LoadLazySpecializations() const { + loadLazySpecializationsImpl(); } llvm::FoldingSetVector & @@ -558,7 +520,7 @@ ClassTemplateDecl::getSpecializations() const { llvm::FoldingSetVector & ClassTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(/*PartialOnly = */ true); + LoadLazySpecializations(); return getCommonPtr()->PartialSpecializations; } @@ -572,15 +534,12 @@ ClassTemplateDecl::newCommon(ASTContext &C) const { ClassTemplateSpecializationDecl * ClassTemplateDecl::findSpecialization(ArrayRef Args, void *&InsertPos) { - auto *Common = getCommonPtr(); - return findSpecializationImpl(Common->Specializations, InsertPos, Args); + return findSpecializationImpl(getSpecializations(), InsertPos, Args); } void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos) { - auto *Common = getCommonPtr(); - addSpecializationImpl(Common->Specializations, D, - InsertPos); + addSpecializationImpl(getSpecializations(), D, InsertPos); } ClassTemplatePartialSpecializationDecl * @@ -925,14 +884,6 @@ TemplateArgumentList::CreateCopy(ASTContext &Context, return new (Mem) TemplateArgumentList(Args); } -unsigned TemplateArgumentList::ComputeODRHash(ArrayRef 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, @@ -1275,9 +1226,8 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, DeclarationName(), nullptr, nullptr); } -void VarTemplateDecl::LoadLazySpecializations( - bool OnlyPartial/*=false*/) const { - loadLazySpecializationsImpl(OnlyPartial); +void VarTemplateDecl::LoadLazySpecializations() const { + loadLazySpecializationsImpl(); } llvm::FoldingSetVector & @@ -1288,7 +1238,7 @@ VarTemplateDecl::getSpecializations() const { llvm::FoldingSetVector & VarTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(/*PartialOnly = */ true); + LoadLazySpecializations(); return getCommonPtr()->PartialSpecializations; } @@ -1302,14 +1252,12 @@ VarTemplateDecl::newCommon(ASTContext &C) const { VarTemplateSpecializationDecl * VarTemplateDecl::findSpecialization(ArrayRef Args, void *&InsertPos) { - auto *Common = getCommonPtr(); - return findSpecializationImpl(Common->Specializations, InsertPos, Args); + return findSpecializationImpl(getSpecializations(), InsertPos, Args); } void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos) { - auto *Common = getCommonPtr(); - addSpecializationImpl(Common->Specializations, D, InsertPos); + addSpecializationImpl(getSpecializations(), D, InsertPos); } VarTemplatePartialSpecializationDecl * diff --git a/interpreter/llvm-project/clang/lib/AST/ODRHash.cpp b/interpreter/llvm-project/clang/lib/AST/ODRHash.cpp index ffc48ee7cb95a..2dbc259138a89 100644 --- a/interpreter/llvm-project/clang/lib/AST/ODRHash.cpp +++ b/interpreter/llvm-project/clang/lib/AST/ODRHash.cpp @@ -812,21 +812,6 @@ 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 Args; - if (auto *CTSD = dyn_cast(D)) - Args = CTSD->getTemplateArgs().asArray(); - else if (auto *VTSD = dyn_cast(D)) - Args = VTSD->getTemplateArgs().asArray(); - else if (auto *FD = dyn_cast(D)) - if (FD->getTemplateSpecializationArgs()) - Args = FD->getTemplateSpecializationArgs()->asArray(); - - for (auto &TA : Args) - AddTemplateArgument(TA); } namespace { diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp index cb2793b2b06db..c006d0e2676c4 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp @@ -7602,23 +7602,14 @@ void ASTReader::CompleteRedeclChain(const Decl *D) { } } - RedeclarableTemplateDecl *Template = nullptr; - ArrayRef Args; - if (auto *CTSD = dyn_cast(D)) { - Template = CTSD->getSpecializedTemplate(); - Args = CTSD->getTemplateArgs().asArray(); - } else if (auto *VTSD = dyn_cast(D)) { - Template = VTSD->getSpecializedTemplate(); - Args = VTSD->getTemplateArgs().asArray(); - } else if (auto *FD = dyn_cast(D)) { - if (auto *Tmplt = FD->getPrimaryTemplate()) { - Template = Tmplt; - Args = FD->getTemplateSpecializationArgs()->asArray(); - } - } - - if (Template) - Template->loadLazySpecializationsImpl(Args); + if (auto *CTSD = dyn_cast(D)) + CTSD->getSpecializedTemplate()->LoadLazySpecializations(); + if (auto *VTSD = dyn_cast(D)) + VTSD->getSpecializedTemplate()->LoadLazySpecializations(); + if (auto *FD = dyn_cast(D)) { + if (auto *Template = FD->getPrimaryTemplate()) + Template->LoadLazySpecializations(); + } } CXXCtorInitializer ** diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp index 1d697b2ae87a1..110f55f8c0f49 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp @@ -88,8 +88,6 @@ namespace clang { const SourceLocation ThisDeclLoc; using RecordData = ASTReader::RecordData; - using LazySpecializationInfo - = RedeclarableTemplateDecl::LazySpecializationInfo; TypeID DeferredTypeID = 0; unsigned AnonymousDeclNumber = 0; @@ -136,16 +134,9 @@ namespace clang { return Record.readString(); } - LazySpecializationInfo ReadLazySpecializationInfo() { - DeclID ID = readDeclID(); - unsigned Hash = Record.readInt(); - bool IsPartial = Record.readInt(); - return LazySpecializationInfo(ID, Hash, IsPartial); - } - - void readDeclIDList(SmallVectorImpl &IDs) { + void readDeclIDList(SmallVectorImpl &IDs) { for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I) - IDs.push_back(ReadLazySpecializationInfo()); + IDs.push_back(readDeclID()); } Decl *readDecl() { @@ -276,7 +267,7 @@ namespace clang { template static void AddLazySpecializations(T *D, - SmallVectorImpl& IDs) { + SmallVectorImpl& IDs) { if (IDs.empty()) return; @@ -286,11 +277,12 @@ namespace clang { auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations; if (auto &Old = LazySpecializations) { - IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].DeclID); + IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); llvm::sort(IDs); IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); } - auto *Result = new (C) LazySpecializationInfo[1 + IDs.size()]; + + auto *Result = new (C) serialization::DeclID[1 + IDs.size()]; *Result = IDs.size(); std::copy(IDs.begin(), IDs.end(), Result + 1); @@ -328,7 +320,7 @@ namespace clang { void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D, llvm::SmallVectorImpl&); + void UpdateDecl(Decl *D, SmallVectorImpl &); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -2462,7 +2454,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 SpecIDs; + SmallVector SpecIDs; readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -2490,7 +2482,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 SpecIDs; + SmallVector SpecIDs; readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -2592,7 +2584,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This FunctionTemplateDecl owns a CommonPtr; read it. - SmallVector SpecIDs; + SmallVector SpecIDs; readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -4203,9 +4195,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); - using LazySpecializationInfo - = RedeclarableTemplateDecl::LazySpecializationInfo; - llvm::SmallVector PendingLazySpecializationIDs; + SmallVector PendingLazySpecializationIDs; if (UpdI != DeclUpdateOffsets.end()) { auto UpdateOffsets = std::move(UpdI->second); @@ -4475,7 +4465,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { } void ASTDeclReader::UpdateDecl(Decl *D, - SmallVectorImpl &PendingLazySpecializationIDs) { + llvm::SmallVectorImpl &PendingLazySpecializationIDs) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { @@ -4488,7 +4478,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(ReadLazySpecializationInfo()); + PendingLazySpecializationIDs.push_back(readDeclID()); break; case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp index ba44c40208171..43389f5cec393 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp @@ -5286,29 +5286,12 @@ 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 Args; - if (auto *CTSD = dyn_cast(Spec)) - Args = CTSD->getTemplateArgs().asArray(); - else if (auto *VTSD = dyn_cast(Spec)) - Args = VTSD->getTemplateArgs().asArray(); - else if (auto *FD = dyn_cast(Spec)) - Args = FD->getTemplateSpecializationArgs()->asArray(); - assert(Args.size()); - Record.push_back(TemplateArgumentList::ComputeODRHash(Args)); - bool IsPartialSpecialization - = isa(Spec) || - isa(Spec); - Record.push_back(IsPartialSpecialization); - break; - } + case UPD_CXX_ADDED_FUNCTION_DEFINITION: case UPD_CXX_ADDED_VAR_DEFINITION: break; diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp index dcca7f14e6f10..42583c09f009e 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp @@ -175,11 +175,11 @@ namespace clang { Record.AddSourceLocation(typeParams->getRAngleLoc()); } - /// Collect the first declaration from each module file that provides a - /// declaration of D. - void CollectFirstDeclFromEachModule(const Decl *D, bool IncludeLocal, - llvm::MapVector &Firsts) { - + /// 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 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,49 +187,10 @@ 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 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(D) || - isa(D) || isa(D) && - "Must not be called with other decls"); - llvm::MapVector Firsts; - CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); - - for (const auto &F : Firsts) { - Record.AddDeclRef(F.second); - ArrayRef Args; - if (auto *CTSD = dyn_cast(D)) - Args = CTSD->getTemplateArgs().asArray(); - else if (auto *VTSD = dyn_cast(D)) - Args = VTSD->getTemplateArgs().asArray(); - else if (auto *FD = dyn_cast(D)) - Args = FD->getTemplateSpecializationArgs()->asArray(); - assert(Args.size()); - Record.push_back(TemplateArgumentList::ComputeODRHash(Args)); - bool IsPartialSpecialization - = isa(D) || - isa(D); - Record.push_back(IsPartialSpecialization); - } - } - /// Get the specialization decl from an entry in the specialization list. template typename RedeclarableTemplateDecl::SpecEntryTraits::DeclType * @@ -242,8 +203,7 @@ namespace clang { decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) { return Common->PartialSpecializations; } - MutableArrayRef - getPartialSpecializations(FunctionTemplateDecl::Common *) { + ArrayRef getPartialSpecializations(FunctionTemplateDecl::Common *) { return std::nullopt; } @@ -260,11 +220,9 @@ namespace clang { assert(!Common->LazySpecializations); } - using LazySpecializationInfo - = RedeclarableTemplateDecl::LazySpecializationInfo; - ArrayRef LazySpecializations; + ArrayRef LazySpecializations; if (auto *LS = Common->LazySpecializations) - LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].DeclID); + LazySpecializations = llvm::ArrayRef(LS + 1, LS[0]); // Add a slot to the record for the number of specializations. unsigned I = Record.size(); @@ -280,20 +238,12 @@ namespace clang { for (auto *D : Specs) { assert(D->isCanonicalDecl() && "non-canonical decl in set"); - AddFirstSpecializationDeclFromEachModule(D, /*IncludeLocal*/true); - } - for (auto &SpecInfo : LazySpecializations) { - Record.push_back(SpecInfo.DeclID); - Record.push_back(SpecInfo.ODRHash); - Record.push_back(SpecInfo.IsPartial); + AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); } + Record.append(LazySpecializations.begin(), LazySpecializations.end()); - // 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; + // Update the size entry we added earlier. + Record[I] = Record.size() - I - 1; } /// Ensure that this template specialization is associated with the specified From 950f33e67cf3c7a2dbd94a099806905fef683e13 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Mon, 16 Dec 2024 13:51:34 +0100 Subject: [PATCH 3/5] [llvm-project] Backport upstream version of lazy template loading https://github.com/llvm/llvm-project/commit/20e904950967c125abc1e91f57e5a373987ff016 Update Cling's ExternalASTSourceWrapper to forward the two new LoadExternalSpecializations functions. --- .../lib/Interpreter/InterpreterCallbacks.cpp | 9 + .../clang/include/clang/AST/DeclTemplate.h | 23 +- .../include/clang/AST/ExternalASTSource.h | 15 + .../clang/Sema/MultiplexExternalSemaSource.h | 6 + .../include/clang/Serialization/ASTBitCodes.h | 13 + .../include/clang/Serialization/ASTReader.h | 48 ++- .../include/clang/Serialization/ASTWriter.h | 17 + .../clang/lib/AST/DeclTemplate.cpp | 107 +++-- .../clang/lib/AST/ExternalASTSource.cpp | 9 + .../llvm-project/clang/lib/AST/ODRHash.cpp | 23 +- .../lib/Sema/MultiplexExternalSemaSource.cpp | 17 + .../clang/lib/Serialization/ASTCommon.h | 1 - .../clang/lib/Serialization/ASTReader.cpp | 236 +++++++++- .../clang/lib/Serialization/ASTReaderDecl.cpp | 103 ++--- .../lib/Serialization/ASTReaderInternals.h | 82 ++++ .../clang/lib/Serialization/ASTWriter.cpp | 210 ++++++++- .../clang/lib/Serialization/ASTWriterDecl.cpp | 106 +++-- .../clang/lib/Serialization/CMakeLists.txt | 1 + .../Serialization/TemplateArgumentHasher.cpp | 406 ++++++++++++++++++ .../Serialization/TemplateArgumentHasher.h | 34 ++ 20 files changed, 1313 insertions(+), 153 deletions(-) create mode 100644 interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.cpp create mode 100644 interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.h diff --git a/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp b/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp index 62330dc138767..fcc36bfa4e654 100644 --- a/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp +++ b/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp @@ -112,6 +112,15 @@ namespace cling { return m_Source->FindExternalVisibleDeclsByName(DC, Name); } + bool LoadExternalSpecializations(const Decl* D, bool OnlyPartial) override { + return m_Source->LoadExternalSpecializations(D, OnlyPartial); + } + + bool LoadExternalSpecializations( + const Decl* D, ArrayRef TemplateArgs) override { + return m_Source->LoadExternalSpecializations(D, TemplateArgs); + } + virtual void completeVisibleDeclsMap(const DeclContext* DC) override { m_Source->completeVisibleDeclsMap(DC); } diff --git a/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h b/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h index 04832a91d6fa8..b3c6ddba566e9 100644 --- a/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h +++ b/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h @@ -749,6 +749,7 @@ class RedeclarableTemplateDecl : public TemplateDecl, } void anchor() override; + protected: template struct SpecEntryTraits { using DeclType = EntryType; @@ -789,13 +790,22 @@ class RedeclarableTemplateDecl : public TemplateDecl, return SpecIterator(isEnd ? Specs.end() : Specs.begin()); } - void loadLazySpecializationsImpl() const; + void loadLazySpecializationsImpl(bool OnlyPartial = false) const; + + bool loadLazySpecializationsImpl(llvm::ArrayRef Args, + TemplateParameterList *TPL = nullptr) const; template typename SpecEntryTraits::DeclType* findSpecializationImpl(llvm::FoldingSetVector &Specs, void *&InsertPos, ProfileArguments &&...ProfileArgs); + template + typename SpecEntryTraits::DeclType * + findSpecializationLocally(llvm::FoldingSetVector &Specs, + void *&InsertPos, + ProfileArguments &&...ProfileArgs); + template void addSpecializationImpl(llvm::FoldingSetVector &Specs, EntryType *Entry, void *InsertPos); @@ -811,13 +821,6 @@ class RedeclarableTemplateDecl : public TemplateDecl, llvm::PointerIntPair InstantiatedFromMember; - /// If non-null, points to an array of specializations (including - /// partial specializations) known only by their external declaration IDs. - /// - /// The first value in the array is the number of specializations/partial - /// specializations that follow. - uint32_t *LazySpecializations = nullptr; - /// The set of "injected" template arguments used within this /// template. /// @@ -2301,7 +2304,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 { @@ -3086,7 +3089,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/interpreter/llvm-project/clang/include/clang/AST/ExternalASTSource.h b/interpreter/llvm-project/clang/include/clang/AST/ExternalASTSource.h index a8aa5d993c47c..f6cc3cca45c9d 100644 --- a/interpreter/llvm-project/clang/include/clang/AST/ExternalASTSource.h +++ b/interpreter/llvm-project/clang/include/clang/AST/ExternalASTSource.h @@ -150,6 +150,21 @@ class ExternalASTSource : public RefCountedBase { virtual bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); + /// Load all the external specializations for the Decl \param D if \param + /// OnlyPartial is false. Otherwise, load all the external **partial** + /// specializations for the \param D. + /// + /// Return true if any new specializations get loaded. Return false otherwise. + virtual bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial); + + /// Load all the specializations for the Decl \param D with the same template + /// args specified by \param TemplateArgs. + /// + /// Return true if any new specializations get loaded. Return false otherwise. + virtual bool + LoadExternalSpecializations(const Decl *D, + ArrayRef TemplateArgs); + /// Ensures that the table of all visible declarations inside this /// context is up to date. /// diff --git a/interpreter/llvm-project/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/interpreter/llvm-project/clang/include/clang/Sema/MultiplexExternalSemaSource.h index 2bf91cb5212c5..c77feae25e1a2 100644 --- a/interpreter/llvm-project/clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/interpreter/llvm-project/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -97,6 +97,12 @@ class MultiplexExternalSemaSource : public ExternalSemaSource { bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override; + bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override; + + bool + LoadExternalSpecializations(const Decl *D, + ArrayRef TemplateArgs) override; + /// Ensures that the table of all visible declarations inside this /// context is up to date. void completeVisibleDeclsMap(const DeclContext *DC) override; diff --git a/interpreter/llvm-project/clang/include/clang/Serialization/ASTBitCodes.h b/interpreter/llvm-project/clang/include/clang/Serialization/ASTBitCodes.h index fdd64f2abbe93..2b59cd1e2c133 100644 --- a/interpreter/llvm-project/clang/include/clang/Serialization/ASTBitCodes.h +++ b/interpreter/llvm-project/clang/include/clang/Serialization/ASTBitCodes.h @@ -695,6 +695,13 @@ enum ASTRecordTypes { /// Record code for an unterminated \#pragma clang assume_nonnull begin /// recorded in a preamble. PP_ASSUME_NONNULL_LOC = 67, + + /// Record code for updated specialization + UPDATE_SPECIALIZATION = 73, + + CXX_ADDED_TEMPLATE_SPECIALIZATION = 74, + + CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION = 75, }; /// Record types used within a source manager block. @@ -1523,6 +1530,12 @@ enum DeclCode { /// An ImplicitConceptSpecializationDecl record. DECL_IMPLICIT_CONCEPT_SPECIALIZATION, + // A decls specilization record. + DECL_SPECIALIZATIONS, + + // A decls specilization record. + DECL_PARTIAL_SPECIALIZATIONS, + DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION }; diff --git a/interpreter/llvm-project/clang/include/clang/Serialization/ASTReader.h b/interpreter/llvm-project/clang/include/clang/Serialization/ASTReader.h index 2dab1ea863771..1cf493ba22a9b 100644 --- a/interpreter/llvm-project/clang/include/clang/Serialization/ASTReader.h +++ b/interpreter/llvm-project/clang/include/clang/Serialization/ASTReader.h @@ -340,6 +340,9 @@ class ASTIdentifierLookupTrait; /// The on-disk hash table(s) used for DeclContext name lookup. struct DeclContextLookupTable; +/// The on-disk hash table(s) used for specialization decls. +struct LazySpecializationInfoLookupTable; + } // namespace reader } // namespace serialization @@ -603,21 +606,41 @@ class ASTReader llvm::DenseMap Lookups; + using SpecLookupTableTy = + llvm::DenseMap; + /// Map from decls to specialized decls. + SpecLookupTableTy SpecializationsLookups; + /// Split partial specialization from specialization to speed up lookups. + SpecLookupTableTy PartialSpecializationsLookups; + + bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, + const Decl *D); + bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, + const Decl *D, + ArrayRef TemplateArgs); + // Updates for visible decls can occur for other contexts than just the // TU, and when we read those update records, the actual context may not // be available yet, so have this pending map using the ID as a key. It - // will be realized when the context is actually loaded. - struct PendingVisibleUpdate { + // will be realized when the data is actually loaded. + struct UpdateData { ModuleFile *Mod; const unsigned char *Data; }; - using DeclContextVisibleUpdates = SmallVector; + using DeclContextVisibleUpdates = SmallVector; /// Updates to the visible declarations of declaration contexts that /// haven't been loaded yet. llvm::DenseMap PendingVisibleUpdates; + using SpecializationsUpdate = SmallVector; + using SpecializationsUpdateMap = + llvm::DenseMap; + SpecializationsUpdateMap PendingSpecializationsUpdates; + SpecializationsUpdateMap PendingPartialSpecializationsUpdates; + /// The set of C++ or Objective-C classes that have forward /// declarations that have not yet been linked to their definitions. llvm::SmallPtrSet PendingDefinitions; @@ -644,6 +667,11 @@ class ASTReader llvm::BitstreamCursor &Cursor, uint64_t Offset, serialization::DeclID ID); + bool ReadSpecializations(ModuleFile &M, llvm::BitstreamCursor &Cursor, + uint64_t Offset, Decl *D, bool IsPartial); + void AddSpecializations(const Decl *D, const unsigned char *Data, + ModuleFile &M, bool IsPartial); + /// A vector containing identifiers that have already been /// loaded. /// @@ -1350,6 +1378,14 @@ class ASTReader const serialization::reader::DeclContextLookupTable * getLoadedLookupTables(DeclContext *Primary) const; + /// Get the loaded specializations lookup tables for \p D, + /// if any. + serialization::reader::LazySpecializationInfoLookupTable * + getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial); + + /// If we have any unloaded specialization for \p D + bool haveUnloadedSpecializations(const Decl *D) const; + private: struct ImportedModule { ModuleFile *Mod; @@ -1989,6 +2025,12 @@ class ASTReader unsigned BlockID, uint64_t *StartOfBlockOffset = nullptr); + bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override; + + bool + LoadExternalSpecializations(const Decl *D, + ArrayRef TemplateArgs) override; + /// Finds all the visible declarations with a given name. /// The current implementation of this method just loads the entire /// lookup table as unmaterialized references. diff --git a/interpreter/llvm-project/clang/include/clang/Serialization/ASTWriter.h b/interpreter/llvm-project/clang/include/clang/Serialization/ASTWriter.h index de69f99003d82..d74a5842eaead 100644 --- a/interpreter/llvm-project/clang/include/clang/Serialization/ASTWriter.h +++ b/interpreter/llvm-project/clang/include/clang/Serialization/ASTWriter.h @@ -385,6 +385,13 @@ class ASTWriter : public ASTDeserializationListener, /// record containing modifications to them. DeclUpdateMap DeclUpdates; + /// Mapping from decl templates and its new specialization in the + /// current TU. + using SpecializationUpdateMap = + llvm::MapVector>; + SpecializationUpdateMap SpecializationsUpdates; + SpecializationUpdateMap PartialSpecializationsUpdates; + using FirstLatestDeclMap = llvm::DenseMap; /// Map of first declarations from a chained PCH that point to the @@ -527,6 +534,12 @@ class ASTWriter : public ASTDeserializationListener, bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC); bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext *DC); + void GenerateSpecializationInfoLookupTable( + const NamedDecl *D, llvm::SmallVectorImpl &Specializations, + llvm::SmallVectorImpl &LookupTable, bool IsPartial); + uint64_t WriteSpecializationInfoLookupTable( + const NamedDecl *D, llvm::SmallVectorImpl &Specializations, + bool IsPartial); void GenerateNameLookupTable(const DeclContext *DC, llvm::SmallVectorImpl &LookupTable); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); @@ -538,6 +551,7 @@ class ASTWriter : public ASTDeserializationListener, void WriteReferencedSelectorsPool(Sema &SemaRef); void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule); + void WriteSpecializationsUpdates(bool IsPartial); void WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord); void WriteDeclContextVisibleUpdate(const DeclContext *DC); void WriteFPPragmaOptions(const FPOptionsOverride &Opts); @@ -564,6 +578,9 @@ class ASTWriter : public ASTDeserializationListener, unsigned DeclEnumAbbrev = 0; unsigned DeclObjCIvarAbbrev = 0; unsigned DeclCXXMethodAbbrev = 0; + unsigned DeclSpecializationsAbbrev = 0; + unsigned DeclPartialSpecializationsAbbrev = 0; + unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0; unsigned DeclTemplateCXXMethodAbbrev = 0; unsigned DeclMemberSpecializedCXXMethodAbbrev = 0; diff --git a/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp b/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp index 7d7556e670f95..9045de0e69eef 100644 --- a/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp +++ b/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp @@ -16,7 +16,9 @@ #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" @@ -331,25 +333,39 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c return Common; } -void RedeclarableTemplateDecl::loadLazySpecializationsImpl() 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]); - } +void RedeclarableTemplateDecl::loadLazySpecializationsImpl( + bool OnlyPartial /*=false*/) const { + auto *ExternalSource = getASTContext().getExternalSource(); + if (!ExternalSource) + return; + + ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), + OnlyPartial); + return; } -template +bool RedeclarableTemplateDecl::loadLazySpecializationsImpl( + ArrayRef Args, TemplateParameterList *TPL) const { + auto *ExternalSource = getASTContext().getExternalSource(); + if (!ExternalSource) + return false; + + // If TPL is not null, it implies that we're loading specializations for + // partial templates. We need to load all specializations in such cases. + if (TPL) + return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), + /*OnlyPartial=*/false); + + return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), + Args); +} + +template typename RedeclarableTemplateDecl::SpecEntryTraits::DeclType * -RedeclarableTemplateDecl::findSpecializationImpl( +RedeclarableTemplateDecl::findSpecializationLocally( llvm::FoldingSetVector &Specs, void *&InsertPos, - ProfileArguments&&... ProfileArgs) { - using SETraits = SpecEntryTraits; + ProfileArguments &&...ProfileArgs) { + using SETraits = RedeclarableTemplateDecl::SpecEntryTraits; llvm::FoldingSetNodeID ID; EntryType::Profile(ID, std::forward(ProfileArgs)..., @@ -358,6 +374,24 @@ RedeclarableTemplateDecl::findSpecializationImpl( return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr; } +template +typename RedeclarableTemplateDecl::SpecEntryTraits::DeclType * +RedeclarableTemplateDecl::findSpecializationImpl( + llvm::FoldingSetVector &Specs, void *&InsertPos, + ProfileArguments &&...ProfileArgs) { + + if (auto *Found = findSpecializationLocally( + Specs, InsertPos, std::forward(ProfileArgs)...)) + return Found; + + if (!loadLazySpecializationsImpl( + std::forward(ProfileArgs)...)) + return nullptr; + + return findSpecializationLocally( + Specs, InsertPos, std::forward(ProfileArgs)...); +} + template void RedeclarableTemplateDecl::addSpecializationImpl( llvm::FoldingSetVector &Specializations, EntryType *Entry, @@ -366,10 +400,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 +481,14 @@ FunctionTemplateDecl::getSpecializations() const { FunctionDecl * FunctionTemplateDecl::findSpecialization(ArrayRef 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(getSpecializations(), Info, + auto *Common = getCommonPtr(); + addSpecializationImpl(Common->Specializations, Info, InsertPos); } @@ -508,8 +548,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 & @@ -520,7 +561,7 @@ ClassTemplateDecl::getSpecializations() const { llvm::FoldingSetVector & ClassTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(); + LoadLazySpecializations(/*PartialOnly = */ true); return getCommonPtr()->PartialSpecializations; } @@ -534,12 +575,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const { ClassTemplateSpecializationDecl * ClassTemplateDecl::findSpecialization(ArrayRef 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(getSpecializations(), D, InsertPos); + auto *Common = getCommonPtr(); + addSpecializationImpl(Common->Specializations, D, + InsertPos); } ClassTemplatePartialSpecializationDecl * @@ -1226,8 +1270,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 & @@ -1238,7 +1283,7 @@ VarTemplateDecl::getSpecializations() const { llvm::FoldingSetVector & VarTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(); + LoadLazySpecializations(/*PartialOnly = */ true); return getCommonPtr()->PartialSpecializations; } @@ -1252,12 +1297,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const { VarTemplateSpecializationDecl * VarTemplateDecl::findSpecialization(ArrayRef 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(getSpecializations(), D, InsertPos); + auto *Common = getCommonPtr(); + addSpecializationImpl(Common->Specializations, D, InsertPos); } VarTemplatePartialSpecializationDecl * diff --git a/interpreter/llvm-project/clang/lib/AST/ExternalASTSource.cpp b/interpreter/llvm-project/clang/lib/AST/ExternalASTSource.cpp index fbb1114a6ea3a..954c3b39d89f9 100644 --- a/interpreter/llvm-project/clang/lib/AST/ExternalASTSource.cpp +++ b/interpreter/llvm-project/clang/lib/AST/ExternalASTSource.cpp @@ -104,6 +104,15 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, return false; } +bool ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) { + return false; +} + +bool ExternalASTSource::LoadExternalSpecializations( + const Decl *D, ArrayRef) { + return false; +} + void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {} void ExternalASTSource::FindExternalLexicalDecls( diff --git a/interpreter/llvm-project/clang/lib/AST/ODRHash.cpp b/interpreter/llvm-project/clang/lib/AST/ODRHash.cpp index 2dbc259138a89..2b9c29f2a276c 100644 --- a/interpreter/llvm-project/clang/lib/AST/ODRHash.cpp +++ b/interpreter/llvm-project/clang/lib/AST/ODRHash.cpp @@ -803,15 +803,20 @@ void ODRHash::AddDecl(const Decl *D) { AddDeclarationName(ND->getDeclName()); - const auto *Specialization = - dyn_cast(D); - AddBoolean(Specialization); - if (Specialization) { - const TemplateArgumentList &List = Specialization->getTemplateArgs(); - ID.AddInteger(List.size()); - 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 Args; + if (auto *CTSD = dyn_cast(D)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast(D)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast(D)) + if (FD->getTemplateSpecializationArgs()) + Args = FD->getTemplateSpecializationArgs()->asArray(); + + for (auto &TA : Args) + AddTemplateArgument(TA); } namespace { diff --git a/interpreter/llvm-project/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/interpreter/llvm-project/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 058e22cb2b814..4b86d738f87a0 100644 --- a/interpreter/llvm-project/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/interpreter/llvm-project/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -115,6 +115,23 @@ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { return AnyDeclsFound; } +bool MultiplexExternalSemaSource::LoadExternalSpecializations( + const Decl *D, bool OnlyPartial) { + bool Loaded = false; + for (size_t i = 0; i < Sources.size(); ++i) + Loaded |= Sources[i]->LoadExternalSpecializations(D, OnlyPartial); + return Loaded; +} + +bool MultiplexExternalSemaSource::LoadExternalSpecializations( + const Decl *D, ArrayRef TemplateArgs) { + bool AnyNewSpecsLoaded = false; + for (size_t i = 0; i < Sources.size(); ++i) + AnyNewSpecsLoaded |= + Sources[i]->LoadExternalSpecializations(D, TemplateArgs); + return AnyNewSpecsLoaded; +} + void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){ for(size_t i = 0; i < Sources.size(); ++i) Sources[i]->completeVisibleDeclsMap(DC); diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTCommon.h b/interpreter/llvm-project/clang/lib/Serialization/ASTCommon.h index 296642e3674a4..485809f234113 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTCommon.h +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTCommon.h @@ -23,7 +23,6 @@ namespace serialization { enum DeclUpdateKind { UPD_CXX_ADDED_IMPLICIT_MEMBER, - UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, UPD_CXX_ADDED_FUNCTION_DEFINITION, UPD_CXX_ADDED_VAR_DEFINITION, diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp index c006d0e2676c4..795d774844d2b 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp @@ -12,6 +12,7 @@ #include "ASTCommon.h" #include "ASTReaderInternals.h" +#include "TemplateArgumentHasher.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -1223,6 +1224,41 @@ void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type, } } +ModuleFile * +LazySpecializationInfoLookupTrait::ReadFileRef(const unsigned char *&d) { + using namespace llvm::support; + + uint32_t ModuleFileID = + endian::readNext(d); + return Reader.getLocalModuleFile(F, ModuleFileID); +} + +LazySpecializationInfoLookupTrait::internal_key_type +LazySpecializationInfoLookupTrait::ReadKey(const unsigned char *d, unsigned) { + using namespace llvm::support; + return endian::readNext(d); +} + +std::pair +LazySpecializationInfoLookupTrait::ReadKeyDataLength(const unsigned char *&d) { + return readULEBKeyDataLength(d); +} + +void LazySpecializationInfoLookupTrait::ReadDataInto(internal_key_type, + const unsigned char *d, + unsigned DataLen, + data_type_builder &Val) { + using namespace llvm::support; + + for (unsigned NumDecls = + DataLen / sizeof(serialization::reader::LazySpecializationInfo); + NumDecls; --NumDecls) { + LocalDeclID LocalID = + endian::readNext(d); + Val.insert(Reader.getGlobalDeclID(F, LocalID)); + } +} + bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, BitstreamCursor &Cursor, uint64_t Offset, @@ -1308,7 +1344,52 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M, // We can't safely determine the primary context yet, so delay attaching the // lookup table until we're done with recursive deserialization. auto *Data = (const unsigned char*)Blob.data(); - PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data}); + PendingVisibleUpdates[ID].push_back(UpdateData{&M, Data}); + return false; +} + +void ASTReader::AddSpecializations(const Decl *D, const unsigned char *Data, + ModuleFile &M, bool IsPartial) { + D = D->getCanonicalDecl(); + auto &SpecLookups = + IsPartial ? PartialSpecializationsLookups : SpecializationsLookups; + SpecLookups[D].Table.add(&M, Data, + reader::LazySpecializationInfoLookupTrait(*this, M)); +} + +bool ASTReader::ReadSpecializations(ModuleFile &M, BitstreamCursor &Cursor, + uint64_t Offset, Decl *D, bool IsPartial) { + assert(Offset != 0); + + SavedStreamPosition SavedPosition(Cursor); + if (llvm::Error Err = Cursor.JumpToBit(Offset)) { + Error(std::move(Err)); + return true; + } + + RecordData Record; + StringRef Blob; + Expected MaybeCode = Cursor.ReadCode(); + if (!MaybeCode) { + Error(MaybeCode.takeError()); + return true; + } + unsigned Code = MaybeCode.get(); + + Expected MaybeRecCode = Cursor.readRecord(Code, Record, &Blob); + if (!MaybeRecCode) { + Error(MaybeRecCode.takeError()); + return true; + } + unsigned RecCode = MaybeRecCode.get(); + if (RecCode != DECL_SPECIALIZATIONS && + RecCode != DECL_PARTIAL_SPECIALIZATIONS) { + Error("Expected decl specs block"); + return true; + } + + auto *Data = (const unsigned char *)Blob.data(); + AddSpecializations(D, Data, M, IsPartial); return false; } @@ -3443,7 +3524,33 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, unsigned Idx = 0; serialization::DeclID ID = ReadDeclID(F, Record, Idx); auto *Data = (const unsigned char*)Blob.data(); - PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data}); + PendingVisibleUpdates[ID].push_back(UpdateData{&F, Data}); + // If we've already loaded the decl, perform the updates when we finish + // loading this block. + if (Decl *D = GetExistingDecl(ID)) + PendingUpdateRecords.push_back( + PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); + break; + } + + case CXX_ADDED_TEMPLATE_SPECIALIZATION: { + unsigned Idx = 0; + GlobalDeclID ID = ReadDeclID(F, Record, Idx); + auto *Data = (const unsigned char *)Blob.data(); + PendingSpecializationsUpdates[ID].push_back(UpdateData{&F, Data}); + // If we've already loaded the decl, perform the updates when we finish + // loading this block. + if (Decl *D = GetExistingDecl(ID)) + PendingUpdateRecords.push_back( + PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); + break; + } + + case CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION: { + unsigned Idx = 0; + GlobalDeclID ID = ReadDeclID(F, Record, Idx); + auto *Data = (const unsigned char *)Blob.data(); + PendingPartialSpecializationsUpdates[ID].push_back(UpdateData{&F, Data}); // If we've already loaded the decl, perform the updates when we finish // loading this block. if (Decl *D = GetExistingDecl(ID)) @@ -7602,13 +7709,28 @@ void ASTReader::CompleteRedeclChain(const Decl *D) { } } - if (auto *CTSD = dyn_cast(D)) - CTSD->getSpecializedTemplate()->LoadLazySpecializations(); - if (auto *VTSD = dyn_cast(D)) - VTSD->getSpecializedTemplate()->LoadLazySpecializations(); - if (auto *FD = dyn_cast(D)) { - if (auto *Template = FD->getPrimaryTemplate()) - Template->LoadLazySpecializations(); + RedeclarableTemplateDecl *Template = nullptr; + ArrayRef Args; + if (auto *CTSD = dyn_cast(D)) { + Template = CTSD->getSpecializedTemplate(); + Args = CTSD->getTemplateArgs().asArray(); + } else if (auto *VTSD = dyn_cast(D)) { + Template = VTSD->getSpecializedTemplate(); + Args = VTSD->getTemplateArgs().asArray(); + } else if (auto *FD = dyn_cast(D)) { + if (auto *Tmplt = FD->getPrimaryTemplate()) { + Template = Tmplt; + Args = FD->getTemplateSpecializationArgs()->asArray(); + } + } + + if (Template) { + // For partitial specialization, load all the specializations for safety. + if (isa(D)) + Template->loadLazySpecializationsImpl(); + else + Template->loadLazySpecializationsImpl(Args); } } @@ -7893,6 +8015,86 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { return ReadStmtFromStream(*Loc.F); } +bool ASTReader::LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, + const Decl *D) { + assert(D); + + auto It = SpecLookups.find(D); + if (It == SpecLookups.end()) + return false; + + // Get Decl may violate the iterator from SpecializationsLookups so we store + // the DeclIDs in ahead. + llvm::SmallVector Infos = + It->second.Table.findAll(); + + // Since we've loaded all the specializations, we can erase it from + // the lookup table. + SpecLookups.erase(It); + + bool NewSpecsFound = false; + Deserializing LookupResults(this); + for (auto &Info : Infos) { + if (GetExistingDecl(Info)) + continue; + NewSpecsFound = true; + GetDecl(Info); + } + + return NewSpecsFound; +} + +bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) { + assert(D); + + bool NewSpecsFound = + LoadExternalSpecializationsImpl(PartialSpecializationsLookups, D); + if (OnlyPartial) + return NewSpecsFound; + + NewSpecsFound |= LoadExternalSpecializationsImpl(SpecializationsLookups, D); + return NewSpecsFound; +} + +bool ASTReader::LoadExternalSpecializationsImpl( + SpecLookupTableTy &SpecLookups, const Decl *D, + ArrayRef TemplateArgs) { + assert(D); + + auto It = SpecLookups.find(D); + if (It == SpecLookups.end()) + return false; + + Deserializing LookupResults(this); + auto HashValue = StableHashForTemplateArguments(TemplateArgs); + + // Get Decl may violate the iterator from SpecLookups + llvm::SmallVector Infos = + It->second.Table.find(HashValue); + + bool NewSpecsFound = false; + for (auto &Info : Infos) { + if (GetExistingDecl(Info)) + continue; + NewSpecsFound = true; + GetDecl(Info); + } + + return NewSpecsFound; +} + +bool ASTReader::LoadExternalSpecializations( + const Decl *D, ArrayRef TemplateArgs) { + assert(D); + + bool NewDeclsFound = LoadExternalSpecializationsImpl( + PartialSpecializationsLookups, D, TemplateArgs); + NewDeclsFound |= + LoadExternalSpecializationsImpl(SpecializationsLookups, D, TemplateArgs); + + return NewDeclsFound; +} + void ASTReader::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Decls) { @@ -8067,6 +8269,22 @@ ASTReader::getLoadedLookupTables(DeclContext *Primary) const { return I == Lookups.end() ? nullptr : &I->second; } +serialization::reader::LazySpecializationInfoLookupTable * +ASTReader::getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial) { + assert(D->isCanonicalDecl()); + auto &LookupTable = + IsPartial ? PartialSpecializationsLookups : SpecializationsLookups; + auto I = LookupTable.find(D); + return I == LookupTable.end() ? nullptr : &I->second; +} + +bool ASTReader::haveUnloadedSpecializations(const Decl *D) const { + assert(D->isCanonicalDecl()); + return (PartialSpecializationsLookups.find(D) != + PartialSpecializationsLookups.end()) || + (SpecializationsLookups.find(D) != SpecializationsLookups.end()); +} + /// Under non-PCH compilation the consumer receives the objc methods /// before receiving the implementation, and codegen depends on this. /// We simulate this by deserializing and passing to consumer the methods of the diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp index 110f55f8c0f49..daefc0c5241c8 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp @@ -134,11 +134,6 @@ namespace clang { return Record.readString(); } - void readDeclIDList(SmallVectorImpl &IDs) { - for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I) - IDs.push_back(readDeclID()); - } - Decl *readDecl() { return Record.readDecl(); } @@ -265,30 +260,6 @@ namespace clang { : Reader(Reader), Record(Record), Loc(Loc), ThisDeclID(thisDeclID), ThisDeclLoc(ThisDeclLoc) {} - template static - void AddLazySpecializations(T *D, - SmallVectorImpl& IDs) { - if (IDs.empty()) - return; - - // FIXME: We should avoid this pattern of getting the ASTContext. - ASTContext &C = D->getASTContext(); - - auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations; - - if (auto &Old = LazySpecializations) { - IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); - llvm::sort(IDs); - IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); - } - - auto *Result = new (C) serialization::DeclID[1 + IDs.size()]; - *Result = IDs.size(); - std::copy(IDs.begin(), IDs.end(), Result + 1); - - LazySpecializations = Result; - } - template static Decl *getMostRecentDeclImpl(Redeclarable *D); static Decl *getMostRecentDeclImpl(...); @@ -317,10 +288,13 @@ namespace clang { /// Determine whether this declaration has a pending body. bool hasPendingBody() const { return HasPendingBody; } + void ReadSpecializations(ModuleFile &M, Decl *D, + llvm::BitstreamCursor &DeclsCursor, bool IsPartial); + void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D, SmallVectorImpl &); + void UpdateDecl(Decl *D); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -2416,6 +2390,16 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl( void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { } +void ASTDeclReader::ReadSpecializations(ModuleFile &M, Decl *D, + llvm::BitstreamCursor &DeclsCursor, + bool IsPartial) { + uint64_t Offset = ReadLocalOffset(); + bool Failed = + Reader.ReadSpecializations(M, DeclsCursor, Offset, D, IsPartial); + (void)Failed; + assert(!Failed); +} + ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); @@ -2454,9 +2438,8 @@ 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 SpecIDs; - readDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true); } if (D->getTemplatedDecl()->TemplateOrInstantiation) { @@ -2482,9 +2465,8 @@ 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 SpecIDs; - readDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true); } } @@ -2584,9 +2566,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This FunctionTemplateDecl owns a CommonPtr; read it. - SmallVector SpecIDs; - readDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false); } } @@ -3826,6 +3806,8 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { switch ((DeclCode)MaybeDeclCode.get()) { case DECL_CONTEXT_LEXICAL: case DECL_CONTEXT_VISIBLE: + case DECL_SPECIALIZATIONS: + case DECL_PARTIAL_SPECIALIZATIONS: llvm_unreachable("Record cannot be de-serialized with readDeclRecord"); case DECL_TYPEDEF: D = TypedefDecl::CreateDeserialized(Context, ID); @@ -4195,8 +4177,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); - SmallVector PendingLazySpecializationIDs; - if (UpdI != DeclUpdateOffsets.end()) { auto UpdateOffsets = std::move(UpdI->second); DeclUpdateOffsets.erase(UpdI); @@ -4234,7 +4214,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID, SourceLocation()); - Reader.UpdateDecl(D, PendingLazySpecializationIDs); + Reader.UpdateDecl(D); // We might have made this declaration interesting. If so, remember that // we need to hand it off to the consumer. @@ -4246,17 +4226,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { } } } - // Add the lazy specializations to the template. - assert((PendingLazySpecializationIDs.empty() || isa(D) || - isa(D)) && - "Must not have pending specializations"); - if (auto *CTD = dyn_cast(D)) - ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs); - else if (auto *FTD = dyn_cast(D)) - ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs); - else if (auto *VTD = dyn_cast(D)) - ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs); - PendingLazySpecializationIDs.clear(); // Load the pending visible updates for this decl context, if it has any. auto I = PendingVisibleUpdates.find(ID); @@ -4271,6 +4240,26 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { reader::ASTDeclContextNameLookupTrait(*this, *Update.Mod)); DC->setHasExternalVisibleStorage(true); } + + // Load the pending specializations update for this decl, if it has any. + if (auto I = PendingSpecializationsUpdates.find(ID); + I != PendingSpecializationsUpdates.end()) { + auto SpecializationUpdates = std::move(I->second); + PendingSpecializationsUpdates.erase(I); + + for (const auto &Update : SpecializationUpdates) + AddSpecializations(D, Update.Data, *Update.Mod, /*IsPartial=*/false); + } + + // Load the pending specializations update for this decl, if it has any. + if (auto I = PendingPartialSpecializationsUpdates.find(ID); + I != PendingPartialSpecializationsUpdates.end()) { + auto SpecializationUpdates = std::move(I->second); + PendingPartialSpecializationsUpdates.erase(I); + + for (const auto &Update : SpecializationUpdates) + AddSpecializations(D, Update.Data, *Update.Mod, /*IsPartial=*/true); + } } void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { @@ -4464,8 +4453,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { } } -void ASTDeclReader::UpdateDecl(Decl *D, - llvm::SmallVectorImpl &PendingLazySpecializationIDs) { +void ASTDeclReader::UpdateDecl(Decl *D) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { @@ -4476,11 +4464,6 @@ void ASTDeclReader::UpdateDecl(Decl *D, break; } - case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: - // It will be added to the template's lazy specialization set. - PendingLazySpecializationIDs.push_back(readDeclID()); - break; - case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { auto *Anon = readDeclAs(); diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTReaderInternals.h b/interpreter/llvm-project/clang/lib/Serialization/ASTReaderInternals.h index abdea0d56b7f1..fbd297ed69944 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTReaderInternals.h +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTReaderInternals.h @@ -119,6 +119,88 @@ struct DeclContextLookupTable { MultiOnDiskHashTable Table; }; +using LazySpecializationInfo = GlobalDeclID; + +/// Class that performs lookup to specialized decls. +class LazySpecializationInfoLookupTrait { + ASTReader &Reader; + ModuleFile &F; + +public: + // Maximum number of lookup tables we allow before condensing the tables. + static const int MaxTables = 4; + + /// The lookup result is a list of global declaration IDs. + using data_type = SmallVector; + + struct data_type_builder { + data_type &Data; + llvm::DenseSet Found; + + data_type_builder(data_type &D) : Data(D) {} + + void insert(LazySpecializationInfo Info) { + // Just use a linear scan unless we have more than a few IDs. + if (Found.empty() && !Data.empty()) { + if (Data.size() <= 4) { + for (auto I : Found) + if (I == Info) + return; + Data.push_back(Info); + return; + } + + // Switch to tracking found IDs in the set. + Found.insert(Data.begin(), Data.end()); + } + + if (Found.insert(Info).second) + Data.push_back(Info); + } + }; + using hash_value_type = unsigned; + using offset_type = unsigned; + using file_type = ModuleFile *; + + using external_key_type = unsigned; + using internal_key_type = unsigned; + + explicit LazySpecializationInfoLookupTrait(ASTReader &Reader, ModuleFile &F) + : Reader(Reader), F(F) {} + + static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { + return a == b; + } + + static hash_value_type ComputeHash(const internal_key_type &Key) { + return Key; + } + + static internal_key_type GetInternalKey(const external_key_type &Name) { + return Name; + } + + static std::pair + ReadKeyDataLength(const unsigned char *&d); + + internal_key_type ReadKey(const unsigned char *d, unsigned); + + void ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen, + data_type_builder &Val); + + static void MergeDataInto(const data_type &From, data_type_builder &To) { + To.Data.reserve(To.Data.size() + From.size()); + for (LazySpecializationInfo Info : From) + To.insert(Info); + } + + file_type ReadFileRef(const unsigned char *&d); +}; + +struct LazySpecializationInfoLookupTable { + MultiOnDiskHashTable Table; +}; + /// Base class for the trait describing the on-disk hash table for the /// identifiers in an AST file. /// diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp index 43389f5cec393..6d0c4b86a1b5f 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp @@ -13,6 +13,7 @@ #include "ASTCommon.h" #include "ASTReaderInternals.h" #include "MultiOnDiskHashTable.h" +#include "TemplateArgumentHasher.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/AbstractTypeWriter.h" @@ -3930,6 +3931,175 @@ class ASTDeclContextNameLookupTrait { } // namespace +namespace { +class LazySpecializationInfoLookupTrait { + ASTWriter &Writer; + llvm::SmallVector Specs; + +public: + using key_type = unsigned; + using key_type_ref = key_type; + + /// A start and end index into Specs, representing a sequence of decls. + using data_type = std::pair; + using data_type_ref = const data_type &; + + using hash_value_type = unsigned; + using offset_type = unsigned; + + explicit LazySpecializationInfoLookupTrait(ASTWriter &Writer) + : Writer(Writer) {} + + template + data_type getData(Col &&C, Col2 &ExistingInfo) { + unsigned Start = Specs.size(); + for (auto *D : C) { + NamedDecl *ND = getDeclForLocalLookup(Writer.getLangOpts(), + const_cast(D)); + Specs.push_back(GlobalDeclID(Writer.GetDeclRef(ND))); + } + for (const serialization::reader::LazySpecializationInfo &Info : + ExistingInfo) + Specs.push_back(Info); + return std::make_pair(Start, Specs.size()); + } + + data_type ImportData( + const reader::LazySpecializationInfoLookupTrait::data_type &FromReader) { + unsigned Start = Specs.size(); + for (auto ID : FromReader) + Specs.push_back(ID); + return std::make_pair(Start, Specs.size()); + } + + static bool EqualKey(key_type_ref a, key_type_ref b) { return a == b; } + + hash_value_type ComputeHash(key_type Name) { return Name; } + + void EmitFileRef(raw_ostream &Out, ModuleFile *F) const { + assert(Writer.hasChain() && + "have reference to loaded module file but no chain?"); + + using namespace llvm::support; + endian::write(Out, Writer.getChain()->getModuleFileID(F), + llvm::endianness::little); + } + + std::pair EmitKeyDataLength(raw_ostream &Out, + key_type HashValue, + data_type_ref Lookup) { + // 4 bytes for each slot. + unsigned KeyLen = 4; + unsigned DataLen = sizeof(serialization::reader::LazySpecializationInfo) * + (Lookup.second - Lookup.first); + + return emitULEBKeyDataLength(KeyLen, DataLen, Out); + } + + void EmitKey(raw_ostream &Out, key_type HashValue, unsigned) { + using namespace llvm::support; + + endian::Writer LE(Out, llvm::endianness::little); + LE.write(HashValue); + } + + void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup, + unsigned DataLen) { + using namespace llvm::support; + + endian::Writer LE(Out, llvm::endianness::little); + uint64_t Start = Out.tell(); + (void)Start; + for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) { + LE.write(Specs[I]); + } + assert(Out.tell() - Start == DataLen && "Data length is wrong"); + } +}; + +unsigned CalculateODRHashForSpecs(const Decl *Spec) { + ArrayRef Args; + if (auto *CTSD = dyn_cast(Spec)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast(Spec)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast(Spec)) + Args = FD->getTemplateSpecializationArgs()->asArray(); + else + llvm_unreachable("New Specialization Kind?"); + + return StableHashForTemplateArguments(Args); +} +} // namespace + +void ASTWriter::GenerateSpecializationInfoLookupTable( + const NamedDecl *D, llvm::SmallVectorImpl &Specializations, + llvm::SmallVectorImpl &LookupTable, bool IsPartial) { + assert(D->isFirstDecl()); + + // Create the on-disk hash table representation. + MultiOnDiskHashTableGenerator + Generator; + LazySpecializationInfoLookupTrait Trait(*this); + + llvm::DenseMap> + SpecializationMaps; + + for (auto *Specialization : Specializations) { + unsigned HashedValue = CalculateODRHashForSpecs(Specialization); + + auto Iter = SpecializationMaps.find(HashedValue); + if (Iter == SpecializationMaps.end()) + Iter = SpecializationMaps + .try_emplace(HashedValue, + llvm::SmallVector()) + .first; + + Iter->second.push_back(cast(Specialization)); + } + + auto *Lookups = + Chain ? Chain->getLoadedSpecializationsLookupTables(D, IsPartial) + : nullptr; + + for (auto &[HashValue, Specs] : SpecializationMaps) { + SmallVector + ExisitingSpecs; + // We have to merge the lookup table manually here. We can't depend on the + // merge mechanism offered by + // clang::serialization::MultiOnDiskHashTableGenerator since that generator + // assumes the we'll get the same value with the same key. + // And also underlying llvm::OnDiskChainedHashTableGenerator assumes that we + // won't insert the values with the same key twice. So we have to merge the + // lookup table here manually. + if (Lookups) + ExisitingSpecs = Lookups->Table.find(HashValue); + + Generator.insert(HashValue, Trait.getData(Specs, ExisitingSpecs), Trait); + } + + Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr); +} + +uint64_t ASTWriter::WriteSpecializationInfoLookupTable( + const NamedDecl *D, llvm::SmallVectorImpl &Specializations, + bool IsPartial) { + + llvm::SmallString<4096> LookupTable; + GenerateSpecializationInfoLookupTable(D, Specializations, LookupTable, + IsPartial); + + uint64_t Offset = Stream.GetCurrentBitNo(); + RecordData::value_type Record[] = {IsPartial ? DECL_PARTIAL_SPECIALIZATIONS + : DECL_SPECIALIZATIONS}; + Stream.EmitRecordWithBlob(IsPartial ? DeclPartialSpecializationsAbbrev + : DeclSpecializationsAbbrev, + Record, LookupTable); + + return Offset; +} + bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC) { return Result.hasExternalDecls() && @@ -5083,7 +5253,7 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, // Keep writing types, declarations, and declaration update records // until we've emitted all of them. - Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5); + Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/ 6); DeclTypesBlockStartOffset = Stream.GetCurrentBitNo(); WriteTypeAbbrevs(); WriteDeclAbbrevs(); @@ -5106,6 +5276,17 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, WriteTypeDeclOffsets(); if (!DeclUpdatesOffsetsRecord.empty()) Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord); + + if (!SpecializationsUpdates.empty()) { + WriteSpecializationsUpdates(/*IsPartial=*/false); + SpecializationsUpdates.clear(); + } + + if (!PartialSpecializationsUpdates.empty()) { + WriteSpecializationsUpdates(/*IsPartial=*/true); + PartialSpecializationsUpdates.clear(); + } + WriteFileDeclIDsMap(); WriteSourceManagerBlock(Context.getSourceManager(), PP); WriteComments(); @@ -5258,6 +5439,31 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, return backpatchSignature(); } +void ASTWriter::WriteSpecializationsUpdates(bool IsPartial) { + auto RecordType = IsPartial ? CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION + : CXX_ADDED_TEMPLATE_SPECIALIZATION; + + auto Abv = std::make_shared(); + Abv->Add(llvm::BitCodeAbbrevOp(RecordType)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + auto UpdateSpecializationAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + auto &SpecUpdates = + IsPartial ? PartialSpecializationsUpdates : SpecializationsUpdates; + for (auto &SpecializationUpdate : SpecUpdates) { + const NamedDecl *D = SpecializationUpdate.first; + + llvm::SmallString<4096> LookupTable; + GenerateSpecializationInfoLookupTable(D, SpecializationUpdate.second, + LookupTable, IsPartial); + + // Write the lookup table + RecordData::value_type Record[] = {RecordType, getDeclID(D)}; + Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable); + } +} + void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { if (DeclUpdates.empty()) return; @@ -5286,12 +5492,10 @@ 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_FUNCTION_DEFINITION: case UPD_CXX_ADDED_VAR_DEFINITION: break; diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp index 42583c09f009e..f2172b6442aa5 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp @@ -175,11 +175,12 @@ 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 Firsts; + /// Collect the first declaration from each module file that provides a + /// declaration of D. + void CollectFirstDeclFromEachModule( + const Decl *D, bool IncludeLocal, + llvm::MapVector &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 +188,41 @@ 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 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, llvm::SmallVectorImpl &SpecsInMap, + llvm::SmallVectorImpl &PartialSpecsInMap) { + assert((isa(D) || + isa(D) || isa(D)) && + "Must not be called with other decls"); + llvm::MapVector Firsts; + CollectFirstDeclFromEachModule(D, /*IncludeLocal*/ true, Firsts); + + for (const auto &F : Firsts) { + if (isa(F.second)) + PartialSpecsInMap.push_back(F.second); + else + SpecsInMap.push_back(F.second); + } + } + /// Get the specialization decl from an entry in the specialization list. template typename RedeclarableTemplateDecl::SpecEntryTraits::DeclType * @@ -203,7 +235,8 @@ namespace clang { decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) { return Common->PartialSpecializations; } - ArrayRef getPartialSpecializations(FunctionTemplateDecl::Common *) { + MutableArrayRef + getPartialSpecializations(FunctionTemplateDecl::Common *) { return std::nullopt; } @@ -215,35 +248,37 @@ namespace clang { // our chained AST reader, we can just write out the DeclIDs. Otherwise, // we need to resolve them to actual declarations. if (Writer.Chain != Writer.Context->getExternalSource() && - Common->LazySpecializations) { + Writer.Chain && Writer.Chain->haveUnloadedSpecializations(D)) { D->LoadLazySpecializations(); - assert(!Common->LazySpecializations); + assert(!Writer.Chain->haveUnloadedSpecializations(D)); } - ArrayRef LazySpecializations; - if (auto *LS = Common->LazySpecializations) - LazySpecializations = llvm::ArrayRef(LS + 1, LS[0]); - - // Add a slot to the record for the number of specializations. - unsigned I = Record.size(); - Record.push_back(0); - - // AddFirstDeclFromEachModule might trigger deserialization, invalidating - // *Specializations iterators. - llvm::SmallVector Specs; + // AddFirstSpecializationDeclFromEachModule might trigger deserialization, + // invalidating *Specializations iterators. + llvm::SmallVector AllSpecs; for (auto &Entry : Common->Specializations) - Specs.push_back(getSpecializationDecl(Entry)); + AllSpecs.push_back(getSpecializationDecl(Entry)); for (auto &Entry : getPartialSpecializations(Common)) - Specs.push_back(getSpecializationDecl(Entry)); + AllSpecs.push_back(getSpecializationDecl(Entry)); - for (auto *D : Specs) { + llvm::SmallVector Specs; + llvm::SmallVector PartialSpecs; + for (auto *D : AllSpecs) { assert(D->isCanonicalDecl() && "non-canonical decl in set"); - AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); + AddFirstSpecializationDeclFromEachModule(D, Specs, PartialSpecs); + } + + Record.AddOffset(Writer.WriteSpecializationInfoLookupTable( + D, Specs, /*IsPartial=*/false)); + + // Function Template Decl doesn't have partial decls. + if (isa(D)) { + assert(PartialSpecs.empty()); + return; } - Record.append(LazySpecializations.begin(), LazySpecializations.end()); - // Update the size entry we added earlier. - Record[I] = Record.size() - I - 1; + Record.AddOffset(Writer.WriteSpecializationInfoLookupTable( + D, PartialSpecs, /*IsPartial=*/true)); } /// Ensure that this template specialization is associated with the specified @@ -264,8 +299,13 @@ namespace clang { if (Writer.getFirstLocalDecl(Specialization) != Specialization) return; - Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate( - UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization)); + if (isa(Specialization)) + Writer.PartialSpecializationsUpdates[cast(Template)] + .push_back(cast(Specialization)); + else + Writer.SpecializationsUpdates[cast(Template)].push_back( + cast(Specialization)); } }; } @@ -2667,6 +2707,16 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + Abv = std::make_shared(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_SPECIALIZATIONS)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + DeclSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + Abv = std::make_shared(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARTIAL_SPECIALIZATIONS)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + DeclPartialSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv)); } /// isRequiredDecl - Check if this is a "required" Decl, which must be seen by diff --git a/interpreter/llvm-project/clang/lib/Serialization/CMakeLists.txt b/interpreter/llvm-project/clang/lib/Serialization/CMakeLists.txt index 5a4b3a58e9c45..59a95546ec57d 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/CMakeLists.txt +++ b/interpreter/llvm-project/clang/lib/Serialization/CMakeLists.txt @@ -21,6 +21,7 @@ add_clang_library(clangSerialization ModuleFileExtension.cpp ModuleManager.cpp PCHContainerOperations.cpp + TemplateArgumentHasher.cpp ADDITIONAL_HEADERS ASTCommon.h diff --git a/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.cpp b/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.cpp new file mode 100644 index 0000000000000..fb624546431f8 --- /dev/null +++ b/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.cpp @@ -0,0 +1,406 @@ +//===- TemplateArgumentHasher.cpp - Hash Template Arguments -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "TemplateArgumentHasher.h" +#include "clang/AST/APValue.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/FoldingSet.h" + +using namespace clang; + +namespace { + +class TemplateArgumentHasher { + // If we bail out during the process of calculating hash values for + // template arguments for any reason. We're allowed to do it since + // TemplateArgumentHasher are only required to give the same hash value + // for the same template arguments, but not required to give different + // hash value for different template arguments. + // + // So in the worst case, it is still a valid implementation to give all + // inputs the same BailedOutValue as output. + bool BailedOut = false; + static constexpr unsigned BailedOutValue = 0x12345678; + + llvm::FoldingSetNodeID ID; + +public: + TemplateArgumentHasher() = default; + + void AddTemplateArgument(TemplateArgument TA); + + void AddInteger(unsigned V) { ID.AddInteger(V); } + + unsigned getValue() { + if (BailedOut) + return BailedOutValue; + + return ID.ComputeHash(); + } + + void setBailedOut() { BailedOut = true; } + + void AddType(const Type *T); + void AddQualType(QualType T); + void AddDecl(const Decl *D); + void AddStructuralValue(const APValue &); + void AddTemplateName(TemplateName Name); + void AddDeclarationName(DeclarationName Name); + void AddIdentifierInfo(const IdentifierInfo *II); +}; + +void TemplateArgumentHasher::AddTemplateArgument(TemplateArgument TA) { + const auto Kind = TA.getKind(); + AddInteger(Kind); + + switch (Kind) { + case TemplateArgument::Null: + llvm_unreachable("Expected valid TemplateArgument"); + case TemplateArgument::Type: + AddQualType(TA.getAsType()); + break; + case TemplateArgument::Declaration: + AddDecl(TA.getAsDecl()); + break; + case TemplateArgument::NullPtr: + ID.AddPointer(nullptr); + break; + case TemplateArgument::Integral: { + // There are integrals (e.g.: _BitInt(128)) that cannot be represented as + // any builtin integral type, so we use the hash of APSInt instead. + TA.getAsIntegral().Profile(ID); + break; + } + case TemplateArgument::StructuralValue: + AddQualType(TA.getStructuralValueType()); + AddStructuralValue(TA.getAsStructuralValue()); + break; + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + AddTemplateName(TA.getAsTemplateOrTemplatePattern()); + break; + case TemplateArgument::Expression: + // If we meet expression in template argument, it implies + // that the template is still dependent. It is meaningless + // to get a stable hash for the template. Bail out simply. + BailedOut = true; + break; + case TemplateArgument::Pack: + AddInteger(TA.pack_size()); + for (auto SubTA : TA.pack_elements()) { + AddTemplateArgument(SubTA); + } + break; + } +} + +void TemplateArgumentHasher::AddStructuralValue(const APValue &Value) { + auto Kind = Value.getKind(); + AddInteger(Kind); + + // 'APValue::Profile' uses pointer values to make hash for LValue and + // MemberPointer, but they differ from one compiler invocation to another. + // It may be difficult to handle such cases. Bail out simply. + + if (Kind == APValue::LValue || Kind == APValue::MemberPointer) { + BailedOut = true; + return; + } + + Value.Profile(ID); +} + +void TemplateArgumentHasher::AddTemplateName(TemplateName Name) { + switch (Name.getKind()) { + case TemplateName::Template: + AddDecl(Name.getAsTemplateDecl()); + break; + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName(); + AddTemplateName(QTN->getUnderlyingTemplate()); + break; + } + case TemplateName::OverloadedTemplate: + case TemplateName::AssumedTemplate: + case TemplateName::DependentTemplate: + case TemplateName::SubstTemplateTemplateParm: + case TemplateName::SubstTemplateTemplateParmPack: + BailedOut = true; + break; + case TemplateName::UsingTemplate: { + UsingShadowDecl *USD = Name.getAsUsingShadowDecl(); + if (USD) + AddDecl(USD->getTargetDecl()); + else + BailedOut = true; + break; + } + } +} + +void TemplateArgumentHasher::AddIdentifierInfo(const IdentifierInfo *II) { + assert(II && "Expecting non-null pointer."); + ID.AddString(II->getName()); +} + +void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) { + if (Name.isEmpty()) + return; + + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + AddIdentifierInfo(Name.getAsIdentifierInfo()); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + BailedOut = true; + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + AddQualType(Name.getCXXNameType()); + break; + case DeclarationName::CXXOperatorName: + AddInteger(Name.getCXXOverloadedOperator()); + break; + case DeclarationName::CXXLiteralOperatorName: + AddIdentifierInfo(Name.getCXXLiteralIdentifier()); + break; + case DeclarationName::CXXConversionFunctionName: + AddQualType(Name.getCXXNameType()); + break; + case DeclarationName::CXXUsingDirective: + break; + case DeclarationName::CXXDeductionGuideName: { + if (auto *Template = Name.getCXXDeductionGuideTemplate()) + AddDecl(Template); + } + } +} + +void TemplateArgumentHasher::AddDecl(const Decl *D) { + const NamedDecl *ND = dyn_cast(D); + if (!ND) { + BailedOut = true; + return; + } + + AddDeclarationName(ND->getDeclName()); +} + +void TemplateArgumentHasher::AddQualType(QualType T) { + if (T.isNull()) { + BailedOut = true; + return; + } + SplitQualType split = T.split(); + AddInteger(split.Quals.getAsOpaqueValue()); + AddType(split.Ty); +} + +// Process a Type pointer. Add* methods call back into TemplateArgumentHasher +// while Visit* methods process the relevant parts of the Type. +// Any unhandled type will make the hash computation bail out. +class TypeVisitorHelper : public TypeVisitor { + typedef TypeVisitor Inherited; + llvm::FoldingSetNodeID &ID; + TemplateArgumentHasher &Hash; + +public: + TypeVisitorHelper(llvm::FoldingSetNodeID &ID, TemplateArgumentHasher &Hash) + : ID(ID), Hash(Hash) {} + + void AddDecl(const Decl *D) { + if (D) + Hash.AddDecl(D); + else + Hash.AddInteger(0); + } + + void AddQualType(QualType T) { Hash.AddQualType(T); } + + void AddType(const Type *T) { + if (T) + Hash.AddType(T); + else + Hash.AddInteger(0); + } + + void VisitQualifiers(Qualifiers Quals) { + Hash.AddInteger(Quals.getAsOpaqueValue()); + } + + void Visit(const Type *T) { Inherited::Visit(T); } + + // Unhandled types. Bail out simply. + void VisitType(const Type *T) { Hash.setBailedOut(); } + + void VisitAdjustedType(const AdjustedType *T) { + AddQualType(T->getOriginalType()); + } + + void VisitDecayedType(const DecayedType *T) { + // getDecayedType and getPointeeType are derived from getAdjustedType + // and don't need to be separately processed. + VisitAdjustedType(T); + } + + void VisitArrayType(const ArrayType *T) { + AddQualType(T->getElementType()); + Hash.AddInteger(llvm::to_underlying(T->getSizeModifier())); + VisitQualifiers(T->getIndexTypeQualifiers()); + } + void VisitConstantArrayType(const ConstantArrayType *T) { + T->getSize().Profile(ID); + VisitArrayType(T); + } + + void VisitAttributedType(const AttributedType *T) { + Hash.AddInteger(T->getAttrKind()); + AddQualType(T->getModifiedType()); + } + + void VisitBuiltinType(const BuiltinType *T) { Hash.AddInteger(T->getKind()); } + + void VisitComplexType(const ComplexType *T) { + AddQualType(T->getElementType()); + } + + void VisitDecltypeType(const DecltypeType *T) { + AddQualType(T->getUnderlyingType()); + } + + void VisitDeducedType(const DeducedType *T) { + AddQualType(T->getDeducedType()); + } + + void VisitAutoType(const AutoType *T) { VisitDeducedType(T); } + + void VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T) { + Hash.AddTemplateName(T->getTemplateName()); + VisitDeducedType(T); + } + + void VisitFunctionType(const FunctionType *T) { + AddQualType(T->getReturnType()); + T->getExtInfo().Profile(ID); + Hash.AddInteger(T->isConst()); + Hash.AddInteger(T->isVolatile()); + Hash.AddInteger(T->isRestrict()); + } + + void VisitFunctionNoProtoType(const FunctionNoProtoType *T) { + VisitFunctionType(T); + } + + void VisitFunctionProtoType(const FunctionProtoType *T) { + Hash.AddInteger(T->getNumParams()); + for (auto ParamType : T->getParamTypes()) + AddQualType(ParamType); + + VisitFunctionType(T); + } + + void VisitMemberPointerType(const MemberPointerType *T) { + AddQualType(T->getPointeeType()); + AddType(T->getClass()); + } + + void VisitPackExpansionType(const PackExpansionType *T) { + AddQualType(T->getPattern()); + } + + void VisitParenType(const ParenType *T) { AddQualType(T->getInnerType()); } + + void VisitPointerType(const PointerType *T) { + AddQualType(T->getPointeeType()); + } + + void VisitReferenceType(const ReferenceType *T) { + AddQualType(T->getPointeeTypeAsWritten()); + } + + void VisitLValueReferenceType(const LValueReferenceType *T) { + VisitReferenceType(T); + } + + void VisitRValueReferenceType(const RValueReferenceType *T) { + VisitReferenceType(T); + } + + void + VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { + AddDecl(T->getAssociatedDecl()); + Hash.AddTemplateArgument(T->getArgumentPack()); + } + + void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { + AddDecl(T->getAssociatedDecl()); + AddQualType(T->getReplacementType()); + } + + void VisitTagType(const TagType *T) { AddDecl(T->getDecl()); } + + void VisitRecordType(const RecordType *T) { VisitTagType(T); } + void VisitEnumType(const EnumType *T) { VisitTagType(T); } + + void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { + Hash.AddInteger(T->template_arguments().size()); + for (const auto &TA : T->template_arguments()) { + Hash.AddTemplateArgument(TA); + } + Hash.AddTemplateName(T->getTemplateName()); + } + + void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { + Hash.AddInteger(T->getDepth()); + Hash.AddInteger(T->getIndex()); + Hash.AddInteger(T->isParameterPack()); + } + + void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); } + + void VisitElaboratedType(const ElaboratedType *T) { + AddQualType(T->getNamedType()); + } + + void VisitUnaryTransformType(const UnaryTransformType *T) { + AddQualType(T->getUnderlyingType()); + AddQualType(T->getBaseType()); + } + + void VisitVectorType(const VectorType *T) { + AddQualType(T->getElementType()); + Hash.AddInteger(T->getNumElements()); + Hash.AddInteger(llvm::to_underlying(T->getVectorKind())); + } + + void VisitExtVectorType(const ExtVectorType *T) { VisitVectorType(T); } +}; + +void TemplateArgumentHasher::AddType(const Type *T) { + assert(T && "Expecting non-null pointer."); + TypeVisitorHelper(ID, *this).Visit(T); +} + +} // namespace + +unsigned clang::serialization::StableHashForTemplateArguments( + llvm::ArrayRef Args) { + TemplateArgumentHasher Hasher; + Hasher.AddInteger(Args.size()); + for (TemplateArgument Arg : Args) + Hasher.AddTemplateArgument(Arg); + return Hasher.getValue(); +} diff --git a/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.h b/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.h new file mode 100644 index 0000000000000..f23f1318afbbf --- /dev/null +++ b/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.h @@ -0,0 +1,34 @@ +//===- TemplateArgumentHasher.h - Hash Template Arguments -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/TemplateBase.h" + +namespace clang { +namespace serialization { + +/// Calculate a stable hash value for template arguments. We guarantee that +/// the same template arguments must have the same hashed values. But we don't +/// guarantee that the template arguments with the same hashed value are the +/// same template arguments. +/// +/// ODR hashing may not be the best mechanism to hash the template +/// arguments. ODR hashing is (or perhaps, should be) about determining whether +/// two things are spelled the same way and have the same meaning (as required +/// by the C++ ODR), whereas what we want here is whether they have the same +/// meaning regardless of spelling. Maybe we can get away with reusing ODR +/// hashing anyway, on the basis that any canonical, non-dependent template +/// argument should have the same (invented) spelling in every translation +/// unit, but it is not sure that's true in all cases. There may still be cases +/// where the canonical type includes some aspect of "whatever we saw first", +/// in which case the ODR hash can differ across translation units for +/// non-dependent, canonical template arguments that are spelled differently +/// but have the same meaning. But it is not easy to raise examples. +unsigned StableHashForTemplateArguments(llvm::ArrayRef Args); + +} // namespace serialization +} // namespace clang From 7f96d50cbbabe22d150175cf618bde53b34d2b99 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Tue, 25 Mar 2025 22:16:49 +0100 Subject: [PATCH 4/5] [llvm-project] Fix lazy template loading Backport upstream PR https://github.com/llvm/llvm-project/pull/133057 --- .../clang/lib/AST/DeclTemplate.cpp | 6 --- .../clang/lib/Serialization/ASTReader.cpp | 10 +--- .../Serialization/TemplateArgumentHasher.cpp | 51 +++++++------------ 3 files changed, 20 insertions(+), 47 deletions(-) diff --git a/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp b/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp index 9045de0e69eef..5f8baada8ef80 100644 --- a/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp +++ b/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp @@ -350,12 +350,6 @@ bool RedeclarableTemplateDecl::loadLazySpecializationsImpl( if (!ExternalSource) return false; - // If TPL is not null, it implies that we're loading specializations for - // partial templates. We need to load all specializations in such cases. - if (TPL) - return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), - /*OnlyPartial=*/false); - return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), Args); } diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp index 795d774844d2b..e3831440c7220 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp @@ -7724,14 +7724,8 @@ void ASTReader::CompleteRedeclChain(const Decl *D) { } } - if (Template) { - // For partitial specialization, load all the specializations for safety. - if (isa(D)) - Template->loadLazySpecializationsImpl(); - else - Template->loadLazySpecializationsImpl(Args); - } + if (Template) + Template->loadLazySpecializationsImpl(Args); } CXXCtorInitializer ** diff --git a/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.cpp b/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.cpp index fb624546431f8..69db7320b6e15 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/TemplateArgumentHasher.cpp @@ -21,17 +21,6 @@ using namespace clang; namespace { class TemplateArgumentHasher { - // If we bail out during the process of calculating hash values for - // template arguments for any reason. We're allowed to do it since - // TemplateArgumentHasher are only required to give the same hash value - // for the same template arguments, but not required to give different - // hash value for different template arguments. - // - // So in the worst case, it is still a valid implementation to give all - // inputs the same BailedOutValue as output. - bool BailedOut = false; - static constexpr unsigned BailedOutValue = 0x12345678; - llvm::FoldingSetNodeID ID; public: @@ -41,14 +30,7 @@ class TemplateArgumentHasher { void AddInteger(unsigned V) { ID.AddInteger(V); } - unsigned getValue() { - if (BailedOut) - return BailedOutValue; - - return ID.ComputeHash(); - } - - void setBailedOut() { BailedOut = true; } + unsigned getValue() { return ID.ComputeHash(); } void AddType(const Type *T); void AddQualType(QualType T); @@ -92,8 +74,7 @@ void TemplateArgumentHasher::AddTemplateArgument(TemplateArgument TA) { case TemplateArgument::Expression: // If we meet expression in template argument, it implies // that the template is still dependent. It is meaningless - // to get a stable hash for the template. Bail out simply. - BailedOut = true; + // to get a stable hash for the template. break; case TemplateArgument::Pack: AddInteger(TA.pack_size()); @@ -110,10 +91,9 @@ void TemplateArgumentHasher::AddStructuralValue(const APValue &Value) { // 'APValue::Profile' uses pointer values to make hash for LValue and // MemberPointer, but they differ from one compiler invocation to another. - // It may be difficult to handle such cases. Bail out simply. + // It may be difficult to handle such cases. if (Kind == APValue::LValue || Kind == APValue::MemberPointer) { - BailedOut = true; return; } @@ -135,14 +115,11 @@ void TemplateArgumentHasher::AddTemplateName(TemplateName Name) { case TemplateName::DependentTemplate: case TemplateName::SubstTemplateTemplateParm: case TemplateName::SubstTemplateTemplateParmPack: - BailedOut = true; break; case TemplateName::UsingTemplate: { UsingShadowDecl *USD = Name.getAsUsingShadowDecl(); if (USD) AddDecl(USD->getTargetDecl()); - else - BailedOut = true; break; } } @@ -164,7 +141,6 @@ void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) { case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - BailedOut = true; break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: @@ -191,16 +167,29 @@ void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) { void TemplateArgumentHasher::AddDecl(const Decl *D) { const NamedDecl *ND = dyn_cast(D); if (!ND) { - BailedOut = true; return; } AddDeclarationName(ND->getDeclName()); + + // 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 Args; + if (auto *CTSD = dyn_cast(D)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast(D)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast(D)) + if (FD->getTemplateSpecializationArgs()) + Args = FD->getTemplateSpecializationArgs()->asArray(); + + for (auto &TA : Args) + AddTemplateArgument(TA); } void TemplateArgumentHasher::AddQualType(QualType T) { if (T.isNull()) { - BailedOut = true; return; } SplitQualType split = T.split(); @@ -210,7 +199,6 @@ void TemplateArgumentHasher::AddQualType(QualType T) { // Process a Type pointer. Add* methods call back into TemplateArgumentHasher // while Visit* methods process the relevant parts of the Type. -// Any unhandled type will make the hash computation bail out. class TypeVisitorHelper : public TypeVisitor { typedef TypeVisitor Inherited; llvm::FoldingSetNodeID &ID; @@ -242,9 +230,6 @@ class TypeVisitorHelper : public TypeVisitor { void Visit(const Type *T) { Inherited::Visit(T); } - // Unhandled types. Bail out simply. - void VisitType(const Type *T) { Hash.setBailedOut(); } - void VisitAdjustedType(const AdjustedType *T) { AddQualType(T->getOriginalType()); } From deb3e7af885a573b0d3f73b369642a2a19c3b88a Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Mon, 7 Apr 2025 14:25:47 +0200 Subject: [PATCH 5/5] [llvm-project] Bump to tag ROOT-llvm18-20250407-01 --- interpreter/llvm-project/llvm-project.tag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interpreter/llvm-project/llvm-project.tag b/interpreter/llvm-project/llvm-project.tag index 13158746c5fa1..5233b016951cc 100644 --- a/interpreter/llvm-project/llvm-project.tag +++ b/interpreter/llvm-project/llvm-project.tag @@ -1 +1 @@ -ROOT-llvm18-20250313-01 +ROOT-llvm18-20250407-01