diff --git a/core/dictgen/src/Scanner.cxx b/core/dictgen/src/Scanner.cxx index 63003ba181b1d..de0d633654d79 100644 --- a/core/dictgen/src/Scanner.cxx +++ b/core/dictgen/src/Scanner.cxx @@ -57,8 +57,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 @@ -1054,6 +1052,8 @@ void RScanner::Scan(const clang::ASTContext &C) std::cout<<"File name detected"<(&fInterpreter)); + if (fScanType == EScanType::kTwoPasses) TraverseDecl(C.getTranslationUnitDecl()); diff --git a/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp b/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp index a72d0462e8f8c..9d730563b0305 100644 --- a/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp +++ b/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp @@ -148,6 +148,16 @@ namespace cling { return m_Source->FindExternalVisibleDeclsByName(DC, Name); } + void LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override { + 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 90858d507d658..c4aad0729ce1e 100644 --- a/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h +++ b/interpreter/llvm-project/clang/include/clang/AST/DeclTemplate.h @@ -257,14 +257,14 @@ class TemplateArgumentList final /// stack object. It does not own its template arguments. enum OnStackType { OnStack }; + /// Create stable hash for the given arguments across compiler invocations. + static unsigned ComputeStableHash(ArrayRef Args); + /// Create a new template argument list that copies the given set of /// template arguments. 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 @@ -780,25 +780,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 { @@ -842,16 +823,19 @@ class RedeclarableTemplateDecl : public TemplateDecl, void loadLazySpecializationsImpl(bool OnlyPartial = false) const; - void loadLazySpecializationsImpl(llvm::ArrayRef Args, + bool loadLazySpecializationsImpl(llvm::ArrayRef Args, TemplateParameterList *TPL = nullptr) const; - Decl *loadLazySpecializationImpl(LazySpecializationInfo &LazySpecInfo) 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); @@ -867,13 +851,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. - LazySpecializationInfo *LazySpecializations = nullptr; - /// The set of "injected" template arguments used within this /// template. /// diff --git a/interpreter/llvm-project/clang/include/clang/AST/ExternalASTSource.h b/interpreter/llvm-project/clang/include/clang/AST/ExternalASTSource.h index 5a0e65e36c0e2..09c69b73f04d3 100644 --- a/interpreter/llvm-project/clang/include/clang/AST/ExternalASTSource.h +++ b/interpreter/llvm-project/clang/include/clang/AST/ExternalASTSource.h @@ -150,6 +150,19 @@ 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. + virtual void 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 external specialization 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 b0bb15eccee1d..78fc4f2737c8f 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; + void 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 9ba94da03720e..111e4c56531a0 100644 --- a/interpreter/llvm-project/clang/include/clang/Serialization/ASTBitCodes.h +++ b/interpreter/llvm-project/clang/include/clang/Serialization/ASTBitCodes.h @@ -702,6 +702,8 @@ enum ASTRecordTypes { /// Record code for an unterminated \#pragma clang assume_nonnull begin /// recorded in a preamble. PP_ASSUME_NONNULL_LOC = 67, + + CXX_ADDED_TEMPLATE_SPECIALIZATION = 68, }; /// Record types used within a source manager block. @@ -1520,6 +1522,9 @@ enum DeclCode { /// A HLSLBufferDecl record. DECL_HLSL_BUFFER, + // A decls specilization record. + DECL_SPECIALIZATIONS, + /// An ImplicitConceptSpecializationDecl record. 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 468ba06f88cbe..c574ab845df2e 100644 --- a/interpreter/llvm-project/clang/include/clang/Serialization/ASTReader.h +++ b/interpreter/llvm-project/clang/include/clang/Serialization/ASTReader.h @@ -341,6 +341,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 @@ -596,21 +599,30 @@ class ASTReader llvm::DenseMap Lookups; + /// Map from decls to specialized decls. + llvm::DenseMap + SpecializationsLookups; + // 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; + llvm::DenseMap + PendingSpecializationsUpdates; + /// The set of C++ or Objective-C classes that have forward /// declarations that have not yet been linked to their definitions. llvm::SmallPtrSet PendingDefinitions; @@ -637,6 +649,11 @@ class ASTReader llvm::BitstreamCursor &Cursor, uint64_t Offset, serialization::DeclID ID); + bool ReadSpecializations(ModuleFile &M, llvm::BitstreamCursor &Cursor, + uint64_t Offset, Decl *D); + void AddSpecializations(const Decl *D, const unsigned char *Data, + ModuleFile &M); + /// A vector containing identifiers that have already been /// loaded. /// @@ -1327,6 +1344,11 @@ 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); + private: struct ImportedModule { ModuleFile *Mod; @@ -1963,6 +1985,12 @@ class ASTReader unsigned BlockID, uint64_t *StartOfBlockOffset = nullptr); + void 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 09ee1744e8945..80fc6b7532e7c 100644 --- a/interpreter/llvm-project/clang/include/clang/Serialization/ASTWriter.h +++ b/interpreter/llvm-project/clang/include/clang/Serialization/ASTWriter.h @@ -373,6 +373,10 @@ class ASTWriter : public ASTDeserializationListener, /// record containing modifications to them. DeclUpdateMap DeclUpdates; + using SpecializationUpdateMap = + llvm::MapVector>; + SpecializationUpdateMap SpecializationsUpdates; + using FirstLatestDeclMap = llvm::DenseMap; /// Map of first declarations from a chained PCH that point to the @@ -517,6 +521,13 @@ 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); + uint64_t WriteSpecializationInfoLookupTable( + const NamedDecl *D, + llvm::SmallVectorImpl &Specializations); + void GenerateNameLookupTable(const DeclContext *DC, llvm::SmallVectorImpl &LookupTable); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); @@ -528,6 +539,7 @@ class ASTWriter : public ASTDeserializationListener, void WriteReferencedSelectorsPool(Sema &SemaRef); void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule); + void WriteSpecializationsUpdates(); void WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord); void WriteDeclContextVisibleUpdate(const DeclContext *DC); void WriteFPPragmaOptions(const FPOptionsOverride &Opts); @@ -554,6 +566,7 @@ class ASTWriter : public ASTDeserializationListener, unsigned DeclEnumAbbrev = 0; unsigned DeclObjCIvarAbbrev = 0; unsigned DeclCXXMethodAbbrev = 0; + unsigned DeclSpecializationsAbbrev = 0; unsigned DeclRefExprAbbrev = 0; unsigned CharacterLiteralAbbrev = 0; diff --git a/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp b/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp index 2ded6d7e08d43..1b4a82e0ffa5f 100644 --- a/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp +++ b/interpreter/llvm-project/clang/lib/AST/DeclTemplate.cpp @@ -16,12 +16,12 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/ODRHash.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" -#include "clang/AST/ODRHash.h" -#include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LLVM.h" @@ -301,53 +301,30 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c } void RedeclarableTemplateDecl::loadLazySpecializationsImpl( - bool OnlyPartial/*=false*/) const { - // Grab the most recent declaration to ensure we've loaded any lazy - // redeclarations of this template. - CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); - if (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]); - } - } -} + bool OnlyPartial /*=false*/) const { + auto *ExternalSource = getASTContext().getExternalSource(); + if (!ExternalSource) + return; -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); + ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), + OnlyPartial); + return; } -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]); - } +bool RedeclarableTemplateDecl::loadLazySpecializationsImpl( + ArrayRef Args, TemplateParameterList *TPL) const { + auto *ExternalSource = getASTContext().getExternalSource(); + if (!ExternalSource) + return false; + + return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), Args); } template typename RedeclarableTemplateDecl::SpecEntryTraits::DeclType * -RedeclarableTemplateDecl::findSpecializationImpl( - llvm::FoldingSetVector &Specs, void *&InsertPos, +RedeclarableTemplateDecl::findSpecializationLocally(llvm::FoldingSetVector &Specs, void *&InsertPos, ProfileArguments&&... ProfileArgs) { - using SETraits = SpecEntryTraits; - - loadLazySpecializationsImpl(std::forward(ProfileArgs)...); + using SETraits = RedeclarableTemplateDecl::SpecEntryTraits; llvm::FoldingSetNodeID ID; EntryType::Profile(ID, std::forward(ProfileArgs)..., @@ -356,6 +333,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; + + // Try to load external specializations if we can't find the specialization + // locally. + if (!loadLazySpecializationsImpl(std::forward(ProfileArgs)...)) + return nullptr; + + return findSpecializationLocally(Specs, InsertPos, + std::forward(ProfileArgs)...); +} + template void RedeclarableTemplateDecl::addSpecializationImpl( llvm::FoldingSetVector &Specializations, EntryType *Entry, @@ -513,7 +508,7 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, } void ClassTemplateDecl::LoadLazySpecializations( - bool OnlyPartial/*=false*/) const { + bool OnlyPartial /*=false*/) const { loadLazySpecializationsImpl(OnlyPartial); } @@ -928,7 +923,20 @@ TemplateArgumentList::CreateCopy(ASTContext &Context, return new (Mem) TemplateArgumentList(Args); } -unsigned TemplateArgumentList::ComputeODRHash(ArrayRef Args) { +unsigned +TemplateArgumentList::ComputeStableHash(ArrayRef Args) { + // FIXME: 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. ODRHash Hasher; for (TemplateArgument TA : Args) Hasher.AddTemplateArgument(TA); @@ -1292,7 +1300,7 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, } void VarTemplateDecl::LoadLazySpecializations( - bool OnlyPartial/*=false*/) const { + bool OnlyPartial /*=false*/) const { loadLazySpecializationsImpl(OnlyPartial); } diff --git a/interpreter/llvm-project/clang/lib/AST/ExternalASTSource.cpp b/interpreter/llvm-project/clang/lib/AST/ExternalASTSource.cpp index fbb1114a6ea3a..764f41b454640 100644 --- a/interpreter/llvm-project/clang/lib/AST/ExternalASTSource.cpp +++ b/interpreter/llvm-project/clang/lib/AST/ExternalASTSource.cpp @@ -104,6 +104,11 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, return false; } +void ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) {} + +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/Sema/MultiplexExternalSemaSource.cpp b/interpreter/llvm-project/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 55e015487f3bf..073323ad238c2 100644 --- a/interpreter/llvm-project/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/interpreter/llvm-project/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -115,6 +115,20 @@ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { return AnyDeclsFound; } +void MultiplexExternalSemaSource::LoadExternalSpecializations( + const Decl *D, bool OnlyPartial) { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->LoadExternalSpecializations(D, OnlyPartial); +} + +bool MultiplexExternalSemaSource::LoadExternalSpecializations( + const Decl *D, ArrayRef TemplateArgs) { + bool AnySpecsLoaded = false; + for (size_t i = 0; i < Sources.size(); ++i) + AnySpecsLoaded |= Sources[i]->LoadExternalSpecializations(D, TemplateArgs); + return AnySpecsLoaded; +} + 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 a797bdb4a534c..729aeb01981a9 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp @@ -1183,6 +1183,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 / serialization::reader::LazySpecializationInfo::Length; + NumDecls; --NumDecls) { + uint32_t LocalID = + endian::readNext(d); + const bool IsPartial = + endian::readNext(d); + Val.insert({Reader.getGlobalDeclID(F, LocalID), IsPartial}); + } +} + bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, BitstreamCursor &Cursor, uint64_t Offset, @@ -1268,7 +1303,49 @@ 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) { + D = D->getCanonicalDecl(); + SpecializationsLookups[D].Table.add( + &M, Data, reader::LazySpecializationInfoLookupTrait(*this, M)); +} + +bool ASTReader::ReadSpecializations(ModuleFile &M, BitstreamCursor &Cursor, + uint64_t Offset, Decl *D) { + 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) { + Error("Expected decl specs block"); + return true; + } + + auto *Data = (const unsigned char *)Blob.data(); + AddSpecializations(D, Data, M); return false; } @@ -3254,7 +3331,20 @@ 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; + serialization::DeclID 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)) @@ -7682,6 +7772,55 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { return ReadStmtFromStream(*Loc.F); } +void ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) { + assert(D); + + auto It = SpecializationsLookups.find(D); + if (It == SpecializationsLookups.end()) + return; + + // Get Decl may violate the iterator from SpecializationsLookups + llvm::SmallVector Infos + = It->second.Table.findAll(); + + // Since we've loaded all the specializations, we can erase it from + // the lookup table. + if (!OnlyPartial) + SpecializationsLookups.erase(It); + + Deserializing LookupResults(this); + for (auto &Info : Infos) + if (!OnlyPartial || Info.IsPartial) + GetDecl(Info.ID); +} + +bool ASTReader::LoadExternalSpecializations( + const Decl *D, ArrayRef TemplateArgs) { + assert(D); + + auto It = SpecializationsLookups.find(D); + if (It == SpecializationsLookups.end()) + return false; + + Deserializing LookupResults(this); + auto HashValue = TemplateArgumentList::ComputeStableHash(TemplateArgs); + + // Get Decl may violate the iterator from SpecializationsLookups + llvm::SmallVector Infos + = It->second.Table.find(HashValue); + + bool AnyNewDeclsFound = false; + for (auto &Info : Infos) { + if (GetExistingDecl(Info.ID)) + continue; + + AnyNewDeclsFound = true; + GetDecl(Info.ID); + } + + return AnyNewDeclsFound; +} + void ASTReader::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Decls) { @@ -7856,6 +7995,13 @@ ASTReader::getLoadedLookupTables(DeclContext *Primary) const { return I == Lookups.end() ? nullptr : &I->second; } +serialization::reader::LazySpecializationInfoLookupTable * +ASTReader::getLoadedSpecializationsLookupTables(const Decl *D) { + assert(D->isCanonicalDecl()); + auto I = SpecializationsLookups.find(D); + return I == SpecializationsLookups.end() ? nullptr : &I->second; +} + /// 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 58c989543bf03..2ce507a2daa33 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp @@ -86,8 +86,6 @@ namespace clang { const SourceLocation ThisDeclLoc; using RecordData = ASTReader::RecordData; - using LazySpecializationInfo - = RedeclarableTemplateDecl::LazySpecializationInfo; TypeID DeferredTypeID = 0; unsigned AnonymousDeclNumber; @@ -134,18 +132,6 @@ 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) { - for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I) - IDs.push_back(ReadLazySpecializationInfo()); - } - Decl *readDecl() { return Record.readDecl(); } @@ -269,29 +255,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].DeclID); - llvm::sort(IDs); - IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); - } - auto *Result = new (C) LazySpecializationInfo[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(...); @@ -323,7 +286,7 @@ namespace clang { void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D, llvm::SmallVectorImpl&); + void UpdateDecl(Decl *D); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -430,6 +393,9 @@ namespace clang { std::pair VisitDeclContext(DeclContext *DC); + void ReadSpecializations(ModuleFile &M, Decl *D, + llvm::BitstreamCursor &Cursor); + template RedeclarableResult VisitRedeclarable(Redeclarable *D); @@ -2308,6 +2274,14 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl( void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { } +void ASTDeclReader::ReadSpecializations(ModuleFile &M, Decl *D, + llvm::BitstreamCursor &DeclsCursor) { + uint64_t Offset = ReadLocalOffset(); + bool Failed = Reader.ReadSpecializations(M, DeclsCursor, Offset, D); + (void)Failed; + assert(!Failed); +} + ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); @@ -2346,9 +2320,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; - readDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor); } if (D->getTemplatedDecl()->TemplateOrInstantiation) { @@ -2374,9 +2346,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; - readDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor); } } @@ -2484,9 +2454,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); } } @@ -3684,6 +3652,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { switch ((DeclCode)MaybeDeclCode.get()) { case DECL_CONTEXT_LEXICAL: case DECL_CONTEXT_VISIBLE: + case DECL_SPECIALIZATIONS: llvm_unreachable("Record cannot be de-serialized with readDeclRecord"); case DECL_TYPEDEF: D = TypedefDecl::CreateDeserialized(Context, ID); @@ -4056,10 +4025,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); - using LazySpecializationInfo - = RedeclarableTemplateDecl::LazySpecializationInfo; - llvm::SmallVector PendingLazySpecializationIDs; - if (UpdI != DeclUpdateOffsets.end()) { auto UpdateOffsets = std::move(UpdI->second); DeclUpdateOffsets.erase(UpdI); @@ -4097,7 +4062,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. @@ -4109,17 +4074,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); @@ -4134,6 +4088,16 @@ 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); + } } void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { @@ -4328,8 +4292,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { } } -void ASTDeclReader::UpdateDecl(Decl *D, - SmallVectorImpl &PendingLazySpecializationIDs) { +void ASTDeclReader::UpdateDecl(Decl *D) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { @@ -4344,11 +4307,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(ReadLazySpecializationInfo()); - 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 5f55185071ed9..f4e255978f3f8 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTReaderInternals.h +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTReaderInternals.h @@ -119,6 +119,102 @@ struct DeclContextLookupTable { MultiOnDiskHashTable Table; }; +struct LazySpecializationInfo { + // The Decl ID for the specialization. + DeclID ID; + // Whether or not this specialization is partial. + bool IsPartial; + + bool operator==(const LazySpecializationInfo &Other) { + assert(ID != Other.ID || IsPartial == Other.IsPartial); + return ID == Other.ID; + } + + // Records the size record in OnDiskHashTable. + // sizeof() may return 8 due to align requirements. + static constexpr unsigned Length = 5; +}; + +/// 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. /// @@ -288,4 +384,29 @@ using HeaderFileInfoLookupTable = } // namespace clang +namespace llvm { +// ID is unique in LazySpecializationInfo, it is redundant to calculate IsPartial. +template <> struct DenseMapInfo { + using LazySpecializationInfo = clang::serialization::reader::LazySpecializationInfo; + using Wrapped = DenseMapInfo; + + static inline LazySpecializationInfo getEmptyKey() { + return {Wrapped::getEmptyKey(), false}; + } + + static inline LazySpecializationInfo getTombstoneKey() { + return {Wrapped::getTombstoneKey(), false}; + } + + static unsigned getHashValue(const LazySpecializationInfo &Key) { + return Wrapped::getHashValue(Key.ID); + } + + static bool isEqual(const LazySpecializationInfo &LHS, + const LazySpecializationInfo &RHS) { + return LHS.ID == RHS.ID; + } +}; +} // end namespace llvm + #endif // LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp index 5c71e51c7daf6..80a0fc12985a2 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTWriter.cpp @@ -3849,6 +3849,152 @@ 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) { + unsigned Start = Specs.size(); + for (auto *D : C) { + bool IsPartial = isa(D); + Specs.push_back({Writer.GetDeclRef(getDeclForLocalLookup( + Writer.getLangOpts(), const_cast(D))), IsPartial}); + } + 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), + 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 = serialization::reader::LazySpecializationInfo::Length * (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, 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, endianness::little); + uint64_t Start = Out.tell(); + (void)Start; + for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) { + LE.write(Specs[I].ID); + LE.write(Specs[I].IsPartial); + } + 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 TemplateArgumentList::ComputeStableHash(Args); +} +} // namespace + +void ASTWriter::GenerateSpecializationInfoLookupTable( + const NamedDecl *D, + llvm::SmallVectorImpl &Specializations, + llvm::SmallVectorImpl &LookupTable) { + 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)); + } + + for (auto Iter : SpecializationMaps) + Generator.insert(Iter.first, Trait.getData(Iter.second), Trait); + + auto *Lookups = + Chain ? Chain->getLoadedSpecializationsLookupTables(D) : nullptr; + Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr); +} + +uint64_t ASTWriter::WriteSpecializationInfoLookupTable( + const NamedDecl *D, + llvm::SmallVectorImpl &Specializations) { + + llvm::SmallString<4096> LookupTable; + GenerateSpecializationInfoLookupTable(D, Specializations, LookupTable); + + uint64_t Offset = Stream.GetCurrentBitNo(); + RecordData::value_type Record[] = {DECL_SPECIALIZATIONS}; + Stream.EmitRecordWithBlob(DeclSpecializationsAbbrev, Record, LookupTable); + + return Offset; +} + bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC) { return Result.hasExternalDecls() && @@ -4984,7 +5130,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(); @@ -5007,6 +5153,10 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, WriteTypeDeclOffsets(); if (!DeclUpdatesOffsetsRecord.empty()) Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord); + + if (!SpecializationsUpdates.empty()) + WriteSpecializationsUpdates(); + WriteFileDeclIDsMap(); WriteSourceManagerBlock(Context.getSourceManager(), PP); WriteComments(); @@ -5159,6 +5309,27 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, return writeUnhashedControlBlock(PP, Context); } +void ASTWriter::WriteSpecializationsUpdates() { + auto Abv = std::make_shared(); + Abv->Add(llvm::BitCodeAbbrevOp(CXX_ADDED_TEMPLATE_SPECIALIZATION)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + auto UpdateSpecializationAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + for (auto &SpecializationUpdate : SpecializationsUpdates) { + const NamedDecl *D = SpecializationUpdate.first; + + llvm::SmallString<4096> LookupTable; + GenerateSpecializationInfoLookupTable(D, SpecializationUpdate.second, + LookupTable); + + // Write the lookup table + RecordData::value_type Record[] = {CXX_ADDED_TEMPLATE_SPECIALIZATION, + getDeclID(D)}; + Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable); + } +} + void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { if (DeclUpdates.empty()) return; @@ -5188,25 +5359,6 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { 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: break; diff --git a/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp b/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp index 5d48ecffa2661..aa303a9e69592 100644 --- a/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/interpreter/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp @@ -179,8 +179,9 @@ namespace clang { /// Collect the first declaration from each module file that provides a /// declaration of D. - void CollectFirstDeclFromEachModule(const Decl *D, bool IncludeLocal, - llvm::MapVector &Firsts) { + 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()) { @@ -195,7 +196,7 @@ namespace clang { /// provides a declaration of D. The intent is to provide a sufficient /// set such that reloading this set will load all current redeclarations. void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) { - llvm::MapVector Firsts; + llvm::MapVector Firsts; CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); for (const auto &F : Firsts) @@ -207,29 +208,15 @@ namespace clang { /// 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); + llvm::SmallVectorImpl &SpecsInMap) { + 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) { - 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); - } + for (const auto &F : Firsts) + SpecsInMap.push_back(F.second); } /// Get the specialization decl from an entry in the specialization list. @@ -256,22 +243,12 @@ namespace clang { // If we have any lazy specializations, and the external AST source is // 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) { + if (Writer.Chain != Writer.Context->getExternalSource() && Writer.Chain && + Writer.Chain->getLoadedSpecializationsLookupTables(D)) { D->LoadLazySpecializations(); - assert(!Common->LazySpecializations); + assert(!Writer.Chain->getLoadedSpecializationsLookupTables(D)); } - using LazySpecializationInfo - = RedeclarableTemplateDecl::LazySpecializationInfo; - ArrayRef LazySpecializations; - if (auto *LS = Common->LazySpecializations) - LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].DeclID); - - // 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; @@ -280,22 +257,15 @@ namespace clang { for (auto &Entry : getPartialSpecializations(Common)) Specs.push_back(getSpecializationDecl(Entry)); + llvm::SmallVector SpecsInOnDiskMap = Specs; + 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); + AddFirstSpecializationDeclFromEachModule(D, SpecsInOnDiskMap); } - // 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; + Record.AddOffset( + Writer.WriteSpecializationInfoLookupTable(D, SpecsInOnDiskMap)); } /// Ensure that this template specialization is associated with the specified @@ -316,8 +286,8 @@ namespace clang { if (Writer.getFirstLocalDecl(Specialization) != Specialization) return; - Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate( - UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization)); + Writer.SpecializationsUpdates[cast(Template)].push_back( + cast(Specialization)); } }; } @@ -2463,6 +2433,11 @@ 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)); } /// isRequiredDecl - Check if this is a "required" Decl, which must be seen by