Author: Haowei Wu Date: 2024-12-06T10:33:57-08:00 New Revision: 12bdeba76eef1c7adf004a280036a7fb690ba573
URL: https://github.com/llvm/llvm-project/commit/12bdeba76eef1c7adf004a280036a7fb690ba573 DIFF: https://github.com/llvm/llvm-project/commit/12bdeba76eef1c7adf004a280036a7fb690ba573.diff LOG: Revert "[Serialization] Support load lazy specialization lazily" This reverts commit b5bd19211118c6d43bc525a4e3fb65d2c750d61e. It brokes multiple llvm bots including clang-x64-windows-msvc Added: Modified: clang/include/clang/AST/DeclTemplate.h clang/include/clang/AST/ExternalASTSource.h clang/include/clang/Sema/MultiplexExternalSemaSource.h clang/include/clang/Serialization/ASTBitCodes.h clang/include/clang/Serialization/ASTReader.h clang/include/clang/Serialization/ASTWriter.h clang/lib/AST/DeclTemplate.cpp clang/lib/AST/ExternalASTSource.cpp clang/lib/AST/ODRHash.cpp clang/lib/Sema/MultiplexExternalSemaSource.cpp clang/lib/Serialization/ASTCommon.h clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTReaderInternals.h clang/lib/Serialization/ASTWriter.cpp clang/lib/Serialization/ASTWriterDecl.cpp clang/lib/Serialization/CMakeLists.txt clang/test/Modules/odr_hash.cpp clang/test/OpenMP/target_parallel_ast_print.cpp clang/test/OpenMP/target_teams_ast_print.cpp clang/test/OpenMP/task_ast_print.cpp clang/test/OpenMP/teams_ast_print.cpp clang/unittests/Serialization/CMakeLists.txt Removed: clang/lib/Serialization/TemplateArgumentHasher.cpp clang/lib/Serialization/TemplateArgumentHasher.h clang/test/Modules/recursive-instantiations.cppm clang/unittests/Serialization/LoadSpecLazilyTest.cpp ################################################################################ diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index dd92d40b804232..e4bf54c3d77b7f 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -735,7 +735,6 @@ class RedeclarableTemplateDecl : public TemplateDecl, } void anchor() override; - protected: template <typename EntryType> struct SpecEntryTraits { using DeclType = EntryType; @@ -776,22 +775,13 @@ class RedeclarableTemplateDecl : public TemplateDecl, return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin()); } - void loadLazySpecializationsImpl(bool OnlyPartial = false) const; - - bool loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args, - TemplateParameterList *TPL = nullptr) const; + void loadLazySpecializationsImpl() const; template <class EntryType, typename ...ProfileArguments> typename SpecEntryTraits<EntryType>::DeclType* findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos, ProfileArguments &&...ProfileArgs); - template <class EntryType, typename... ProfileArguments> - typename SpecEntryTraits<EntryType>::DeclType * - findSpecializationLocally(llvm::FoldingSetVector<EntryType> &Specs, - void *&InsertPos, - ProfileArguments &&...ProfileArgs); - template <class Derived, class EntryType> void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs, EntryType *Entry, void *InsertPos); @@ -806,6 +796,13 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// was explicitly specialized. llvm::PointerIntPair<RedeclarableTemplateDecl *, 1, bool> 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. + GlobalDeclID *LazySpecializations = nullptr; }; /// Pointer to the common data shared by all declarations of this @@ -2286,7 +2283,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 { @@ -3036,7 +3033,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/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index 9f968ba05b4466..582ed7c65f58ca 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -152,21 +152,6 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> { 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<TemplateArgument> TemplateArgs); - /// Ensures that the table of all visible declarations inside this /// context is up to date. /// diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h index 0c92c52854c9e7..3d1906d8699265 100644 --- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -97,12 +97,6 @@ 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<TemplateArgument> 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/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index af0e08d800bf28..fd834c14ce790f 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -733,13 +733,6 @@ enum ASTRecordTypes { /// Record code for Sema's vector of functions/blocks with effects to /// be verified. DECLS_WITH_EFFECTS_TO_VERIFY = 72, - - /// 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. @@ -1509,12 +1502,6 @@ 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/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index f91052be5e1291..f739fe688c110d 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -354,9 +354,6 @@ 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 @@ -635,40 +632,20 @@ class ASTReader llvm::DenseMap<const DeclContext *, serialization::reader::DeclContextLookupTable> Lookups; - using SpecLookupTableTy = - llvm::DenseMap<const Decl *, - serialization::reader::LazySpecializationInfoLookupTable>; - /// 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<TemplateArgument> 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 data is actually loaded. - struct UpdateData { + // will be realized when the context is actually loaded. + struct PendingVisibleUpdate { ModuleFile *Mod; const unsigned char *Data; }; - using DeclContextVisibleUpdates = SmallVector<UpdateData, 1>; + using DeclContextVisibleUpdates = SmallVector<PendingVisibleUpdate, 1>; /// Updates to the visible declarations of declaration contexts that /// haven't been loaded yet. llvm::DenseMap<GlobalDeclID, DeclContextVisibleUpdates> PendingVisibleUpdates; - using SpecializationsUpdate = SmallVector<UpdateData, 1>; - using SpecializationsUpdateMap = - llvm::DenseMap<GlobalDeclID, SpecializationsUpdate>; - 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<Decl *, 4> PendingDefinitions; @@ -701,11 +678,6 @@ class ASTReader llvm::BitstreamCursor &Cursor, uint64_t Offset, GlobalDeclID 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. /// @@ -1447,14 +1419,6 @@ 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; @@ -2112,12 +2076,6 @@ class ASTReader unsigned BlockID, uint64_t *StartOfBlockOffset = nullptr); - bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override; - - bool - LoadExternalSpecializations(const Decl *D, - ArrayRef<TemplateArgument> 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/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index d98d23decbdc0d..e418fdea44a0a9 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -423,13 +423,6 @@ class ASTWriter : public ASTDeserializationListener, /// Only meaningful for reduced BMI. DeclUpdateMap DeclUpdatesFromGMF; - /// Mapping from decl templates and its new specialization in the - /// current TU. - using SpecializationUpdateMap = - llvm::MapVector<const NamedDecl *, SmallVector<const Decl *>>; - SpecializationUpdateMap SpecializationsUpdates; - SpecializationUpdateMap PartialSpecializationsUpdates; - using FirstLatestDeclMap = llvm::DenseMap<Decl *, Decl *>; /// Map of first declarations from a chained PCH that point to the @@ -582,12 +575,6 @@ class ASTWriter : public ASTDeserializationListener, bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC); - void GenerateSpecializationInfoLookupTable( - const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations, - llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial); - uint64_t WriteSpecializationInfoLookupTable( - const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations, - bool IsPartial); void GenerateNameLookupTable(ASTContext &Context, const DeclContext *DC, llvm::SmallVectorImpl<char> &LookupTable); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, @@ -603,7 +590,6 @@ class ASTWriter : public ASTDeserializationListener, void WriteDeclAndTypes(ASTContext &Context); void PrepareWritingSpecialDecls(Sema &SemaRef); void WriteSpecialDeclRecords(Sema &SemaRef); - void WriteSpecializationsUpdates(bool IsPartial); void WriteDeclUpdatesBlocks(ASTContext &Context, RecordDataImpl &OffsetsRecord); void WriteDeclContextVisibleUpdate(ASTContext &Context, @@ -633,9 +619,6 @@ 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/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 40ee3753c24227..1da3f26bf23cd5 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -16,9 +16,7 @@ #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" @@ -350,39 +348,26 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c return Common; } -void RedeclarableTemplateDecl::loadLazySpecializationsImpl( - bool OnlyPartial /*=false*/) const { - auto *ExternalSource = getASTContext().getExternalSource(); - if (!ExternalSource) - return; - - ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), - OnlyPartial); - return; -} - -bool RedeclarableTemplateDecl::loadLazySpecializationsImpl( - ArrayRef<TemplateArgument> 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); +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(); + GlobalDeclID *Specs = CommonBasePtr->LazySpecializations; + CommonBasePtr->LazySpecializations = nullptr; + unsigned SpecSize = (*Specs++).getRawValue(); + for (unsigned I = 0; I != SpecSize; ++I) + (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + } } -template <class EntryType, typename... ProfileArguments> +template<class EntryType, typename... ProfileArguments> typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * -RedeclarableTemplateDecl::findSpecializationLocally( +RedeclarableTemplateDecl::findSpecializationImpl( llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos, - ProfileArguments &&...ProfileArgs) { - using SETraits = RedeclarableTemplateDecl::SpecEntryTraits<EntryType>; + ProfileArguments&&... ProfileArgs) { + using SETraits = SpecEntryTraits<EntryType>; llvm::FoldingSetNodeID ID; EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)..., @@ -391,24 +376,6 @@ RedeclarableTemplateDecl::findSpecializationLocally( return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr; } -template <class EntryType, typename... ProfileArguments> -typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * -RedeclarableTemplateDecl::findSpecializationImpl( - llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos, - ProfileArguments &&...ProfileArgs) { - - if (auto *Found = findSpecializationLocally( - Specs, InsertPos, std::forward<ProfileArguments>(ProfileArgs)...)) - return Found; - - if (!loadLazySpecializationsImpl( - std::forward<ProfileArguments>(ProfileArgs)...)) - return nullptr; - - return findSpecializationLocally( - Specs, InsertPos, std::forward<ProfileArguments>(ProfileArgs)...); -} - template<class Derived, class EntryType> void RedeclarableTemplateDecl::addSpecializationImpl( llvm::FoldingSetVector<EntryType> &Specializations, EntryType *Entry, @@ -417,14 +384,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 @@ -482,14 +445,12 @@ FunctionTemplateDecl::getSpecializations() const { FunctionDecl * FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> 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<FunctionTemplateDecl>(Common->Specializations, Info, + addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info, InsertPos); } @@ -549,9 +510,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<ClassTemplateSpecializationDecl> & @@ -562,7 +522,7 @@ ClassTemplateDecl::getSpecializations() const { llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> & ClassTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(/*PartialOnly = */ true); + LoadLazySpecializations(); return getCommonPtr()->PartialSpecializations; } @@ -576,15 +536,12 @@ ClassTemplateDecl::newCommon(ASTContext &C) const { ClassTemplateSpecializationDecl * ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> 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<ClassTemplateDecl>(Common->Specializations, D, - InsertPos); + addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos); } ClassTemplatePartialSpecializationDecl * @@ -1302,9 +1259,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<VarTemplateSpecializationDecl> & @@ -1315,7 +1271,7 @@ VarTemplateDecl::getSpecializations() const { llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> & VarTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(/*PartialOnly = */ true); + LoadLazySpecializations(); return getCommonPtr()->PartialSpecializations; } @@ -1329,14 +1285,12 @@ VarTemplateDecl::newCommon(ASTContext &C) const { VarTemplateSpecializationDecl * VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> 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<VarTemplateDecl>(Common->Specializations, D, InsertPos); + addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos); } VarTemplatePartialSpecializationDecl * diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp index 543846c0093af8..7a14cc7d50ed05 100644 --- a/clang/lib/AST/ExternalASTSource.cpp +++ b/clang/lib/AST/ExternalASTSource.cpp @@ -96,15 +96,6 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, return false; } -bool ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) { - return false; -} - -bool ExternalASTSource::LoadExternalSpecializations( - const Decl *D, ArrayRef<TemplateArgument>) { - return false; -} - void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {} void ExternalASTSource::FindExternalLexicalDecls( diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 7c5c287e6c15ba..645ca6f0e7b715 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -818,20 +818,15 @@ void ODRHash::AddDecl(const Decl *D) { 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<TemplateArgument> Args; - if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) - Args = CTSD->getTemplateArgs().asArray(); - else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) - Args = VTSD->getTemplateArgs().asArray(); - else if (auto *FD = dyn_cast<FunctionDecl>(D)) - if (FD->getTemplateSpecializationArgs()) - Args = FD->getTemplateSpecializationArgs()->asArray(); - - for (auto &TA : Args) - AddTemplateArgument(TA); + const auto *Specialization = + dyn_cast<ClassTemplateSpecializationDecl>(D); + AddBoolean(Specialization); + if (Specialization) { + const TemplateArgumentList &List = Specialization->getTemplateArgs(); + ID.AddInteger(List.size()); + for (const TemplateArgument &TA : List.asArray()) + AddTemplateArgument(TA); + } } namespace { diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 54944267b4868a..cd44483b5cbe04 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -115,23 +115,6 @@ 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<TemplateArgument> 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/clang/lib/Serialization/ASTCommon.h b/clang/lib/Serialization/ASTCommon.h index 7c9ec884ea049d..2a765eafe08951 100644 --- a/clang/lib/Serialization/ASTCommon.h +++ b/clang/lib/Serialization/ASTCommon.h @@ -24,6 +24,7 @@ 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/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 490c690189c8ac..ec85fad3389a1c 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12,7 +12,6 @@ #include "ASTCommon.h" #include "ASTReaderInternals.h" -#include "TemplateArgumentHasher.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -1296,42 +1295,6 @@ void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type, } } -ModuleFile * -LazySpecializationInfoLookupTrait::ReadFileRef(const unsigned char *&d) { - using namespace llvm::support; - - uint32_t ModuleFileID = - endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d); - return Reader.getLocalModuleFile(F, ModuleFileID); -} - -LazySpecializationInfoLookupTrait::internal_key_type -LazySpecializationInfoLookupTrait::ReadKey(const unsigned char *d, unsigned) { - using namespace llvm::support; - return endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d); -} - -std::pair<unsigned, unsigned> -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 = LocalDeclID::get( - Reader, F, - endian::readNext<DeclID, llvm::endianness::little, unaligned>(d)); - Val.insert(Reader.getGlobalDeclID(F, LocalID)); - } -} - bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, BitstreamCursor &Cursor, uint64_t Offset, @@ -1416,52 +1379,7 @@ 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(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<unsigned> MaybeCode = Cursor.ReadCode(); - if (!MaybeCode) { - Error(MaybeCode.takeError()); - return true; - } - unsigned Code = MaybeCode.get(); - - Expected<unsigned> 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); + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data}); return false; } @@ -3540,33 +3458,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, unsigned Idx = 0; GlobalDeclID ID = ReadDeclID(F, Record, Idx); auto *Data = (const unsigned char*)Blob.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}); + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data}); // If we've already loaded the decl, perform the updates when we finish // loading this block. if (Decl *D = GetExistingDecl(ID)) @@ -7762,28 +7654,13 @@ void ASTReader::CompleteRedeclChain(const Decl *D) { } } - RedeclarableTemplateDecl *Template = nullptr; - ArrayRef<TemplateArgument> Args; - if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { - Template = CTSD->getSpecializedTemplate(); - Args = CTSD->getTemplateArgs().asArray(); - } else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) { - Template = VTSD->getSpecializedTemplate(); - Args = VTSD->getTemplateArgs().asArray(); - } else if (auto *FD = dyn_cast<FunctionDecl>(D)) { - if (auto *Tmplt = FD->getPrimaryTemplate()) { - Template = Tmplt; - Args = FD->getTemplateSpecializationArgs()->asArray(); - } - } - - if (Template) { - // For partitial specialization, load all the specializations for safety. - if (isa<ClassTemplatePartialSpecializationDecl, - VarTemplatePartialSpecializationDecl>(D)) - Template->loadLazySpecializationsImpl(); - else - Template->loadLazySpecializationsImpl(Args); + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) + CTSD->getSpecializedTemplate()->LoadLazySpecializations(); + if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) + VTSD->getSpecializedTemplate()->LoadLazySpecializations(); + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + if (auto *Template = FD->getPrimaryTemplate()) + Template->LoadLazySpecializations(); } } @@ -8165,86 +8042,6 @@ 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<serialization::reader::LazySpecializationInfo, 8> 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<TemplateArgument> 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<serialization::reader::LazySpecializationInfo, 8> 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<TemplateArgument> 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<bool(Decl::Kind)> IsKindWeWant, SmallVectorImpl<Decl *> &Decls) { @@ -8424,22 +8221,6 @@ 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/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 0644ff4dfe6827..6ece3ba7af9f4b 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -187,6 +187,11 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { std::string readString() { return Record.readString(); } + void readDeclIDList(SmallVectorImpl<GlobalDeclID> &IDs) { + for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I) + IDs.push_back(readDeclID()); + } + Decl *readDecl() { return Record.readDecl(); } template <typename T> T *readDeclAs() { return Record.readDeclAs<T>(); } @@ -279,6 +284,30 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { : Reader(Reader), MergeImpl(Reader), Record(Record), Loc(Loc), ThisDeclID(thisDeclID), ThisDeclLoc(ThisDeclLoc) {} + template <typename T> + static void AddLazySpecializations(T *D, SmallVectorImpl<GlobalDeclID> &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].getRawValue()); + llvm::sort(IDs); + IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); + } + + auto *Result = new (C) GlobalDeclID[1 + IDs.size()]; + *Result = GlobalDeclID(IDs.size()); + + std::copy(IDs.begin(), IDs.end(), Result + 1); + + LazySpecializations = Result; + } + template <typename DeclT> static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D); static Decl *getMostRecentDeclImpl(...); @@ -303,13 +332,10 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { static void markIncompleteDeclChainImpl(Redeclarable<DeclT> *D); static void markIncompleteDeclChainImpl(...); - void ReadSpecializations(ModuleFile &M, Decl *D, - llvm::BitstreamCursor &DeclsCursor, bool IsPartial); - void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D); + void UpdateDecl(Decl *D, SmallVectorImpl<GlobalDeclID> &); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -2392,16 +2418,6 @@ 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); -} - RedeclarableResult ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); @@ -2440,8 +2456,9 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. - ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false); - ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true); + SmallVector<GlobalDeclID, 32> SpecIDs; + readDeclIDList(SpecIDs); + ASTDeclReader::AddLazySpecializations(D, SpecIDs); } if (D->getTemplatedDecl()->TemplateOrInstantiation) { @@ -2467,8 +2484,9 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This VarTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. - ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false); - ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true); + SmallVector<GlobalDeclID, 32> SpecIDs; + readDeclIDList(SpecIDs); + ASTDeclReader::AddLazySpecializations(D, SpecIDs); } } @@ -2567,7 +2585,9 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This FunctionTemplateDecl owns a CommonPtr; read it. - ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false); + SmallVector<GlobalDeclID, 32> SpecIDs; + readDeclIDList(SpecIDs); + ASTDeclReader::AddLazySpecializations(D, SpecIDs); } } @@ -3857,8 +3877,6 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID 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); @@ -4268,6 +4286,8 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); + SmallVector<GlobalDeclID, 8> PendingLazySpecializationIDs; + if (UpdI != DeclUpdateOffsets.end()) { auto UpdateOffsets = std::move(UpdI->second); DeclUpdateOffsets.erase(UpdI); @@ -4304,7 +4324,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID, SourceLocation()); - Reader.UpdateDecl(D); + Reader.UpdateDecl(D, PendingLazySpecializationIDs); // We might have made this declaration interesting. If so, remember that // we need to hand it off to the consumer. @@ -4314,6 +4334,17 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { } } } + // Add the lazy specializations to the template. + assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) || + isa<FunctionTemplateDecl, VarTemplateDecl>(D)) && + "Must not have pending specializations"); + if (auto *CTD = dyn_cast<ClassTemplateDecl>(D)) + ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs); + else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) + ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs); + else if (auto *VTD = dyn_cast<VarTemplateDecl>(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); @@ -4338,26 +4369,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { FunctionToLambdasMap.erase(IT); } } - - // 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) { @@ -4550,7 +4561,9 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { } } -void ASTDeclReader::UpdateDecl(Decl *D) { +void ASTDeclReader::UpdateDecl( + Decl *D, + llvm::SmallVectorImpl<GlobalDeclID> &PendingLazySpecializationIDs) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { @@ -4561,6 +4574,11 @@ 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<NamespaceDecl>(); diff --git a/clang/lib/Serialization/ASTReaderInternals.h b/clang/lib/Serialization/ASTReaderInternals.h index be0d22d1f4094f..4f7e6f4b2741b7 100644 --- a/clang/lib/Serialization/ASTReaderInternals.h +++ b/clang/lib/Serialization/ASTReaderInternals.h @@ -119,88 +119,6 @@ struct DeclContextLookupTable { MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> 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<LazySpecializationInfo, 4>; - - struct data_type_builder { - data_type &Data; - llvm::DenseSet<LazySpecializationInfo> 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<unsigned, unsigned> - 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<LazySpecializationInfoLookupTrait> Table; -}; - /// Base class for the trait describing the on-disk hash table for the /// identifiers in an AST file. /// diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 83fbb705e48c7c..f8158a654c45aa 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -13,7 +13,6 @@ #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" @@ -4168,175 +4167,6 @@ class ASTDeclContextNameLookupTrait { } // namespace -namespace { -class LazySpecializationInfoLookupTrait { - ASTWriter &Writer; - llvm::SmallVector<serialization::reader::LazySpecializationInfo, 64> 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<unsigned, unsigned>; - using data_type_ref = const data_type &; - - using hash_value_type = unsigned; - using offset_type = unsigned; - - explicit LazySpecializationInfoLookupTrait(ASTWriter &Writer) - : Writer(Writer) {} - - template <typename Col, typename Col2> - data_type getData(Col &&C, Col2 &ExistingInfo) { - unsigned Start = Specs.size(); - for (auto *D : C) { - NamedDecl *ND = getDeclForLocalLookup(Writer.getLangOpts(), - const_cast<NamedDecl *>(D)); - Specs.push_back(GlobalDeclID(Writer.GetDeclRef(ND).getRawValue())); - } - 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<uint32_t>(Out, Writer.getChain()->getModuleFileID(F), - llvm::endianness::little); - } - - std::pair<unsigned, unsigned> 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<uint32_t>(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<DeclID>(Specs[I].getRawValue()); - } - assert(Out.tell() - Start == DataLen && "Data length is wrong"); - } -}; - -unsigned CalculateODRHashForSpecs(const Decl *Spec) { - ArrayRef<TemplateArgument> Args; - if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Spec)) - Args = CTSD->getTemplateArgs().asArray(); - else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Spec)) - Args = VTSD->getTemplateArgs().asArray(); - else if (auto *FD = dyn_cast<FunctionDecl>(Spec)) - Args = FD->getTemplateSpecializationArgs()->asArray(); - else - llvm_unreachable("New Specialization Kind?"); - - return StableHashForTemplateArguments(Args); -} -} // namespace - -void ASTWriter::GenerateSpecializationInfoLookupTable( - const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations, - llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial) { - assert(D->isFirstDecl()); - - // Create the on-disk hash table representation. - MultiOnDiskHashTableGenerator<reader::LazySpecializationInfoLookupTrait, - LazySpecializationInfoLookupTrait> - Generator; - LazySpecializationInfoLookupTrait Trait(*this); - - llvm::DenseMap<unsigned, llvm::SmallVector<const NamedDecl *, 4>> - 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<const NamedDecl *, 4>()) - .first; - - Iter->second.push_back(cast<NamedDecl>(Specialization)); - } - - auto *Lookups = - Chain ? Chain->getLoadedSpecializationsLookupTables(D, IsPartial) - : nullptr; - - for (auto &[HashValue, Specs] : SpecializationMaps) { - SmallVector<serialization::reader::LazySpecializationInfo, 16> - 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<const Decl *> &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() && @@ -5918,7 +5748,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { // Keep writing types, declarations, and declaration update records // until we've emitted all of them. RecordData DeclUpdatesOffsetsRecord; - Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/ 6); + Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5); DeclTypesBlockStartOffset = Stream.GetCurrentBitNo(); WriteTypeAbbrevs(); WriteDeclAbbrevs(); @@ -5992,16 +5822,6 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { FunctionToLambdaMapAbbrev); } - if (!SpecializationsUpdates.empty()) { - WriteSpecializationsUpdates(/*IsPartial=*/false); - SpecializationsUpdates.clear(); - } - - if (!PartialSpecializationsUpdates.empty()) { - WriteSpecializationsUpdates(/*IsPartial=*/true); - PartialSpecializationsUpdates.clear(); - } - const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); // Create a lexical update block containing all of the declarations in the // translation unit that do not come from other AST files. @@ -6045,31 +5865,6 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { WriteDeclContextVisibleUpdate(Context, DC); } -void ASTWriter::WriteSpecializationsUpdates(bool IsPartial) { - auto RecordType = IsPartial ? CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION - : CXX_ADDED_TEMPLATE_SPECIALIZATION; - - auto Abv = std::make_shared<llvm::BitCodeAbbrev>(); - 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).getRawValue()}; - Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable); - } -} - void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context, RecordDataImpl &OffsetsRecord) { if (DeclUpdates.empty()) @@ -6099,10 +5894,12 @@ void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context, 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.AddDeclRef(Update.getDecl()); break; + case UPD_CXX_ADDED_FUNCTION_DEFINITION: case UPD_CXX_ADDED_VAR_DEFINITION: break; diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index b3119607a14043..ad357e30d57529 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -177,12 +177,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<ModuleFile *, const Decl *> &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<ModuleFile*, const Decl*> Firsts; // FIXME: We can skip entries that we know are implied by others. for (const Decl *R = D->getMostRecentDecl(); R; R = R->getPreviousDecl()) { if (R->isFromASTFile()) @@ -190,41 +189,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<ModuleFile *, const Decl *> Firsts; - CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); - for (const auto &F : Firsts) Record.AddDeclRef(F.second); } - /// Add to the record the first template specialization from each module - /// file that provides a declaration of D. We store the DeclId and an - /// ODRHash of the template arguments of D which should provide enough - /// information to load D only if the template instantiator needs it. - void AddFirstSpecializationDeclFromEachModule( - const Decl *D, llvm::SmallVectorImpl<const Decl *> &SpecsInMap, - llvm::SmallVectorImpl<const Decl *> &PartialSpecsInMap) { - assert((isa<ClassTemplateSpecializationDecl>(D) || - isa<VarTemplateSpecializationDecl>(D) || isa<FunctionDecl>(D)) && - "Must not be called with other decls"); - llvm::MapVector<ModuleFile *, const Decl *> Firsts; - CollectFirstDeclFromEachModule(D, /*IncludeLocal*/ true, Firsts); - - for (const auto &F : Firsts) { - if (isa<ClassTemplatePartialSpecializationDecl, - VarTemplatePartialSpecializationDecl>(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 EntryType> typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * @@ -237,9 +205,8 @@ namespace clang { decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) { return Common->PartialSpecializations; } - MutableArrayRef<FunctionTemplateSpecializationInfo> - getPartialSpecializations(FunctionTemplateDecl::Common *) { - return std::nullopt; + ArrayRef<Decl> getPartialSpecializations(FunctionTemplateDecl::Common *) { + return {}; } template<typename DeclTy> @@ -250,37 +217,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 != Record.getASTContext().getExternalSource() && - Writer.Chain && Writer.Chain->haveUnloadedSpecializations(D)) { + Common->LazySpecializations) { D->LoadLazySpecializations(); - assert(!Writer.Chain->haveUnloadedSpecializations(D)); + assert(!Common->LazySpecializations); } - // AddFirstSpecializationDeclFromEachModule might trigger deserialization, - // invalidating *Specializations iterators. - llvm::SmallVector<const Decl *, 16> AllSpecs; + ArrayRef<GlobalDeclID> LazySpecializations; + if (auto *LS = Common->LazySpecializations) + LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].getRawValue()); + + // 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<const Decl*, 16> Specs; for (auto &Entry : Common->Specializations) - AllSpecs.push_back(getSpecializationDecl(Entry)); + Specs.push_back(getSpecializationDecl(Entry)); for (auto &Entry : getPartialSpecializations(Common)) - AllSpecs.push_back(getSpecializationDecl(Entry)); + Specs.push_back(getSpecializationDecl(Entry)); - llvm::SmallVector<const Decl *, 16> Specs; - llvm::SmallVector<const Decl *, 16> PartialSpecs; - for (auto *D : AllSpecs) { + for (auto *D : Specs) { assert(D->isCanonicalDecl() && "non-canonical decl in set"); - AddFirstSpecializationDeclFromEachModule(D, Specs, PartialSpecs); - } - - Record.AddOffset(Writer.WriteSpecializationInfoLookupTable( - D, Specs, /*IsPartial=*/false)); - - // Function Template Decl doesn't have partial decls. - if (isa<FunctionTemplateDecl>(D)) { - assert(PartialSpecs.empty()); - return; + AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); } + Record.append( + DeclIDIterator<GlobalDeclID, DeclID>(LazySpecializations.begin()), + DeclIDIterator<GlobalDeclID, DeclID>(LazySpecializations.end())); - Record.AddOffset(Writer.WriteSpecializationInfoLookupTable( - D, PartialSpecs, /*IsPartial=*/true)); + // Update the size entry we added earlier. + Record[I] = Record.size() - I - 1; } /// Ensure that this template specialization is associated with the specified @@ -301,13 +268,8 @@ namespace clang { if (Writer.getFirstLocalDecl(Specialization) != Specialization) return; - if (isa<ClassTemplatePartialSpecializationDecl, - VarTemplatePartialSpecializationDecl>(Specialization)) - Writer.PartialSpecializationsUpdates[cast<NamedDecl>(Template)] - .push_back(cast<NamedDecl>(Specialization)); - else - Writer.SpecializationsUpdates[cast<NamedDecl>(Template)].push_back( - cast<NamedDecl>(Specialization)); + Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate( + UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization)); } }; } @@ -2812,16 +2774,6 @@ 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<BitCodeAbbrev>(); - Abv->Add(BitCodeAbbrevOp(serialization::DECL_SPECIALIZATIONS)); - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - DeclSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv)); - - Abv = std::make_shared<BitCodeAbbrev>(); - 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/clang/lib/Serialization/CMakeLists.txt b/clang/lib/Serialization/CMakeLists.txt index b1fc0345047f24..99c47c15a2f479 100644 --- a/clang/lib/Serialization/CMakeLists.txt +++ b/clang/lib/Serialization/CMakeLists.txt @@ -23,7 +23,6 @@ add_clang_library(clangSerialization ModuleManager.cpp PCHContainerOperations.cpp ObjectFilePCHContainerReader.cpp - TemplateArgumentHasher.cpp ADDITIONAL_HEADERS ASTCommon.h diff --git a/clang/lib/Serialization/TemplateArgumentHasher.cpp b/clang/lib/Serialization/TemplateArgumentHasher.cpp deleted file mode 100644 index 598f098f526d0f..00000000000000 --- a/clang/lib/Serialization/TemplateArgumentHasher.cpp +++ /dev/null @@ -1,409 +0,0 @@ -//===- 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 diff erent - // hash value for diff erent 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.computeStableHash(); - } - - 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 diff er from one compiler invocation to another. - // It may be diff icult 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; - } - case TemplateName::DeducedTemplate: - AddTemplateName(Name.getAsDeducedTemplateName()->getUnderlying()); - 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<NamedDecl>(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<TypeVisitorHelper> { - typedef TypeVisitor<TypeVisitorHelper> 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<TemplateArgument> Args) { - TemplateArgumentHasher Hasher; - Hasher.AddInteger(Args.size()); - for (TemplateArgument Arg : Args) - Hasher.AddTemplateArgument(Arg); - return Hasher.getValue(); -} diff --git a/clang/lib/Serialization/TemplateArgumentHasher.h b/clang/lib/Serialization/TemplateArgumentHasher.h deleted file mode 100644 index f23f1318afbbf4..00000000000000 --- a/clang/lib/Serialization/TemplateArgumentHasher.h +++ /dev/null @@ -1,34 +0,0 @@ -//===- 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 diff er across translation units for -/// non-dependent, canonical template arguments that are spelled diff erently -/// but have the same meaning. But it is not easy to raise examples. -unsigned StableHashForTemplateArguments(llvm::ArrayRef<TemplateArgument> Args); - -} // namespace serialization -} // namespace clang diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index 4de0e50dbc0eb7..f1de6b3d433ed7 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -3084,8 +3084,8 @@ struct S5 { }; #else S5 s5; -// expected-error@first.h:* {{'PointersAndReferences::S5::x' from module 'FirstModule' is not present in definition of 'PointersAndReferences::S5' in module 'SecondModule'}} -// expected-note@second.h:* {{declaration of 'x' does not match}} +// expected-error@second.h:* {{'PointersAndReferences::S5::x' from module 'SecondModule' is not present in definition of 'PointersAndReferences::S5' in module 'FirstModule'}} +// expected-note@first.h:* {{declaration of 'x' does not match}} #endif #if defined(FIRST) diff --git a/clang/test/Modules/recursive-instantiations.cppm b/clang/test/Modules/recursive-instantiations.cppm deleted file mode 100644 index d5854b0e647e37..00000000000000 --- a/clang/test/Modules/recursive-instantiations.cppm +++ /dev/null @@ -1,40 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/type_traits.cppm -emit-module-interface -o %t/type_traits.pcm -// RUN: %clang_cc1 -std=c++20 %t/test.cpp -fprebuilt-module-path=%t -verify - -//--- type_traits.cppm -export module type_traits; - -export template <typename T> -constexpr bool is_pod_v = __is_pod(T); - -//--- test.cpp -// expected-no-diagnostics -import type_traits; -// Base is either void or wrapper<T>. -template <class Base> struct wrapper : Base {}; -template <> struct wrapper<void> {}; - -// wrap<0>::type<T> is wrapper<T>, wrap<1>::type<T> is wrapper<wrapper<T>>, -// and so on. -template <int N> -struct wrap { - template <class Base> - using type = wrapper<typename wrap<N-1>::template type<Base>>; -}; - -template <> -struct wrap<0> { - template <class Base> - using type = wrapper<Base>; -}; - -inline constexpr int kMaxRank = 40; -template <int N, class Base = void> -using rank = typename wrap<N>::template type<Base>; -using rank_selector_t = rank<kMaxRank>; - -static_assert(is_pod_v<rank_selector_t>, "Must be POD"); diff --git a/clang/test/OpenMP/target_parallel_ast_print.cpp b/clang/test/OpenMP/target_parallel_ast_print.cpp index 3ee98bc525c1bd..7e27ac7b92ca4a 100644 --- a/clang/test/OpenMP/target_parallel_ast_print.cpp +++ b/clang/test/OpenMP/target_parallel_ast_print.cpp @@ -38,6 +38,10 @@ struct S { // CHECK: static int TS; // CHECK-NEXT: #pragma omp threadprivate(S<int>::TS) // CHECK-NEXT: } +// CHECK: template<> struct S<char> { +// CHECK: static char TS; +// CHECK-NEXT: #pragma omp threadprivate(S<char>::TS) +// CHECK-NEXT: } template <typename T, int C> T tmain(T argc, T *argv) { diff --git a/clang/test/OpenMP/target_teams_ast_print.cpp b/clang/test/OpenMP/target_teams_ast_print.cpp index cc47ae92efac0f..8338f2a68f9228 100644 --- a/clang/test/OpenMP/target_teams_ast_print.cpp +++ b/clang/test/OpenMP/target_teams_ast_print.cpp @@ -40,6 +40,10 @@ struct S { // CHECK: static int TS; // CHECK-NEXT: #pragma omp threadprivate(S<int>::TS) // CHECK-NEXT: } +// CHECK: template<> struct S<long> { +// CHECK: static long TS; +// CHECK-NEXT: #pragma omp threadprivate(S<long>::TS) +// CHECK-NEXT: } template <typename T, int C> T tmain(T argc, T *argv) { diff --git a/clang/test/OpenMP/task_ast_print.cpp b/clang/test/OpenMP/task_ast_print.cpp index 30fb7ab75cc87a..2a6b8908a1e2dc 100644 --- a/clang/test/OpenMP/task_ast_print.cpp +++ b/clang/test/OpenMP/task_ast_print.cpp @@ -87,6 +87,10 @@ struct S { // CHECK: static int TS; // CHECK-NEXT: #pragma omp threadprivate(S<int>::TS) // CHECK-NEXT: } +// CHECK: template<> struct S<long> { +// CHECK: static long TS; +// CHECK-NEXT: #pragma omp threadprivate(S<long>::TS) +// CHECK-NEXT: } template <typename T, int C> T tmain(T argc, T *argv) { diff --git a/clang/test/OpenMP/teams_ast_print.cpp b/clang/test/OpenMP/teams_ast_print.cpp index 597a9b2bdbdc5d..0087f71ac9f742 100644 --- a/clang/test/OpenMP/teams_ast_print.cpp +++ b/clang/test/OpenMP/teams_ast_print.cpp @@ -27,6 +27,10 @@ struct S { // CHECK: static int TS; // CHECK-NEXT: #pragma omp threadprivate(S<int>::TS) // CHECK-NEXT: } +// CHECK: template<> struct S<long> { +// CHECK: static long TS; +// CHECK-NEXT: #pragma omp threadprivate(S<long>::TS) +// CHECK-NEXT: } template <typename T, int C> T tmain(T argc, T *argv) { diff --git a/clang/unittests/Serialization/CMakeLists.txt b/clang/unittests/Serialization/CMakeLists.txt index e7005b5d511eba..e7eebd0cb98239 100644 --- a/clang/unittests/Serialization/CMakeLists.txt +++ b/clang/unittests/Serialization/CMakeLists.txt @@ -11,7 +11,6 @@ add_clang_unittest(SerializationTests ModuleCacheTest.cpp NoCommentsTest.cpp PreambleInNamedModulesTest.cpp - LoadSpecLazilyTest.cpp SourceLocationEncodingTest.cpp VarDeclConstantInitTest.cpp ) diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp deleted file mode 100644 index 0e452652a940d5..00000000000000 --- a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp +++ /dev/null @@ -1,262 +0,0 @@ -//== unittests/Serialization/LoadSpecLazily.cpp ----------------------========// -// -// 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/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendAction.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Parse/ParseAST.h" -#include "clang/Serialization/ASTDeserializationListener.h" -#include "clang/Tooling/Tooling.h" -#include "gtest/gtest.h" - -using namespace llvm; -using namespace clang; -using namespace clang::tooling; - -namespace { - -class LoadSpecLazilyTest : public ::testing::Test { - void SetUp() override { - ASSERT_FALSE( - sys::fs::createUniqueDirectory("load-spec-lazily-test", TestDir)); - } - - void TearDown() override { sys::fs::remove_directories(TestDir); } - -public: - SmallString<256> TestDir; - - void addFile(StringRef Path, StringRef Contents) { - ASSERT_FALSE(sys::path::is_absolute(Path)); - - SmallString<256> AbsPath(TestDir); - sys::path::append(AbsPath, Path); - - ASSERT_FALSE( - sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath))); - - std::error_code EC; - llvm::raw_fd_ostream OS(AbsPath, EC); - ASSERT_FALSE(EC); - OS << Contents; - } - - std::string GenerateModuleInterface(StringRef ModuleName, - StringRef Contents) { - std::string FileName = llvm::Twine(ModuleName + ".cppm").str(); - addFile(FileName, Contents); - - IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = - llvm::vfs::createPhysicalFileSystem(); - IntrusiveRefCntPtr<DiagnosticsEngine> Diags = - CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions()); - CreateInvocationOptions CIOpts; - CIOpts.Diags = Diags; - CIOpts.VFS = VFS; - - std::string CacheBMIPath = - llvm::Twine(TestDir + "/" + ModuleName + ".pcm").str(); - std::string PrebuiltModulePath = - "-fprebuilt-module-path=" + TestDir.str().str(); - const char *Args[] = {"clang++", - "-std=c++20", - "--precompile", - PrebuiltModulePath.c_str(), - "-working-directory", - TestDir.c_str(), - "-I", - TestDir.c_str(), - FileName.c_str(), - "-o", - CacheBMIPath.c_str()}; - std::shared_ptr<CompilerInvocation> Invocation = - createInvocation(Args, CIOpts); - EXPECT_TRUE(Invocation); - - CompilerInstance Instance; - Instance.setDiagnostics(Diags.get()); - Instance.setInvocation(Invocation); - Instance.getFrontendOpts().OutputFile = CacheBMIPath; - GenerateModuleInterfaceAction Action; - EXPECT_TRUE(Instance.ExecuteAction(Action)); - EXPECT_FALSE(Diags->hasErrorOccurred()); - - return CacheBMIPath; - } -}; - -enum class CheckingMode { Forbidden, Required }; - -class DeclsReaderListener : public ASTDeserializationListener { - StringRef SpeficiedName; - CheckingMode Mode; - - bool ReadedSpecifiedName = false; - -public: - void DeclRead(GlobalDeclID ID, const Decl *D) override { - auto *ND = dyn_cast<NamedDecl>(D); - if (!ND) - return; - - ReadedSpecifiedName |= ND->getName().contains(SpeficiedName); - if (Mode == CheckingMode::Forbidden) { - EXPECT_FALSE(ReadedSpecifiedName); - } - } - - DeclsReaderListener(StringRef SpeficiedName, CheckingMode Mode) - : SpeficiedName(SpeficiedName), Mode(Mode) {} - - ~DeclsReaderListener() { - if (Mode == CheckingMode::Required) { - EXPECT_TRUE(ReadedSpecifiedName); - } - } -}; - -class LoadSpecLazilyConsumer : public ASTConsumer { - DeclsReaderListener Listener; - -public: - LoadSpecLazilyConsumer(StringRef SpecifiedName, CheckingMode Mode) - : Listener(SpecifiedName, Mode) {} - - ASTDeserializationListener *GetASTDeserializationListener() override { - return &Listener; - } -}; - -class CheckLoadSpecLazilyAction : public ASTFrontendAction { - StringRef SpecifiedName; - CheckingMode Mode; - -public: - std::unique_ptr<ASTConsumer> - CreateASTConsumer(CompilerInstance &CI, StringRef /*Unused*/) override { - return std::make_unique<LoadSpecLazilyConsumer>(SpecifiedName, Mode); - } - - CheckLoadSpecLazilyAction(StringRef SpecifiedName, CheckingMode Mode) - : SpecifiedName(SpecifiedName), Mode(Mode) {} -}; - -TEST_F(LoadSpecLazilyTest, BasicTest) { - GenerateModuleInterface("M", R"cpp( -export module M; -export template <class T> -class A {}; -export class ShouldNotBeLoaded {}; -export class Temp { - A<ShouldNotBeLoaded> AS; -}; - )cpp"); - - const char *test_file_contents = R"cpp( -import M; -A<int> a; - )cpp"; - std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str(); - EXPECT_TRUE( - runToolOnCodeWithArgs(std::make_unique<CheckLoadSpecLazilyAction>( - "ShouldNotBeLoaded", CheckingMode::Forbidden), - test_file_contents, - { - "-std=c++20", - DepArg.c_str(), - "-I", - TestDir.c_str(), - }, - "test.cpp")); -} - -TEST_F(LoadSpecLazilyTest, ChainedTest) { - GenerateModuleInterface("M", R"cpp( -export module M; -export template <class T> -class A {}; - )cpp"); - - GenerateModuleInterface("N", R"cpp( -export module N; -export import M; -export class ShouldNotBeLoaded {}; -export class Temp { - A<ShouldNotBeLoaded> AS; -}; - )cpp"); - - const char *test_file_contents = R"cpp( -import N; -A<int> a; - )cpp"; - std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str(); - EXPECT_TRUE( - runToolOnCodeWithArgs(std::make_unique<CheckLoadSpecLazilyAction>( - "ShouldNotBeLoaded", CheckingMode::Forbidden), - test_file_contents, - { - "-std=c++20", - DepArg.c_str(), - "-I", - TestDir.c_str(), - }, - "test.cpp")); -} - -/// Test that we won't crash due to we may invalidate the lazy specialization -/// lookup table during the loading process. -TEST_F(LoadSpecLazilyTest, ChainedTest2) { - GenerateModuleInterface("M", R"cpp( -export module M; -export template <class T> -class A {}; - -export class B {}; - -export class C { - A<B> D; -}; - )cpp"); - - GenerateModuleInterface("N", R"cpp( -export module N; -export import M; -export class MayBeLoaded {}; - -export class Temp { - A<MayBeLoaded> AS; -}; - -export class ExportedClass {}; - -export template<> class A<ExportedClass> { - A<MayBeLoaded> AS; - A<B> AB; -}; - )cpp"); - - const char *test_file_contents = R"cpp( -import N; -Temp T; -A<ExportedClass> a; - )cpp"; - std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str(); - EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<CheckLoadSpecLazilyAction>( - "MayBeLoaded", CheckingMode::Required), - test_file_contents, - { - "-std=c++20", - DepArg.c_str(), - "-I", - TestDir.c_str(), - }, - "test.cpp")); -} - -} // namespace _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits