[clang] 12bdeba - Revert "[Serialization] Support load lazy specialization lazily"
Haowei Wu via cfe-commits
cfe-commits at lists.llvm.org
Fri Dec 6 10:34:30 PST 2024
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 at first.h:* {{'PointersAndReferences::S5::x' from module 'FirstModule' is not present in definition of 'PointersAndReferences::S5' in module 'SecondModule'}}
-// expected-note at second.h:* {{declaration of 'x' does not match}}
+// expected-error at second.h:* {{'PointersAndReferences::S5::x' from module 'SecondModule' is not present in definition of 'PointersAndReferences::S5' in module 'FirstModule'}}
+// expected-note at 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
More information about the cfe-commits
mailing list