[llvm-branch-commits] [clang] [Serialization] Code cleanups and polish 83233 (PR #83237)
Chuanqi Xu via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Nov 8 01:43:53 PST 2024
https://github.com/ChuanqiXu9 updated https://github.com/llvm/llvm-project/pull/83237
>From 493cb7cdafeb22efa9e9f3c1954b6de1e2665365 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Wed, 28 Feb 2024 11:41:53 +0800
Subject: [PATCH 1/2] [Serialization] Code cleanups and polish 83233
---
clang/include/clang/AST/DeclTemplate.h | 32 +-
clang/include/clang/AST/ExternalASTSource.h | 8 +-
.../clang/Sema/MultiplexExternalSemaSource.h | 4 +-
.../include/clang/Serialization/ASTBitCodes.h | 2 +
clang/include/clang/Serialization/ASTReader.h | 4 +-
clang/lib/AST/DeclTemplate.cpp | 85 ++--
clang/lib/AST/ExternalASTSource.cpp | 10 +-
clang/lib/AST/ODRHash.cpp | 10 -
.../lib/Sema/MultiplexExternalSemaSource.cpp | 13 +-
clang/lib/Serialization/ASTCommon.h | 1 -
clang/lib/Serialization/ASTReader.cpp | 41 +-
clang/lib/Serialization/ASTReaderDecl.cpp | 80 +---
clang/lib/Serialization/ASTReaderInternals.h | 3 +-
clang/lib/Serialization/ASTWriter.cpp | 49 +--
clang/lib/Serialization/ASTWriterDecl.cpp | 53 +--
clang/lib/Serialization/CMakeLists.txt | 1 +
.../Serialization/TemplateArgumentHasher.cpp | 409 ++++++++++++++++++
.../Serialization/TemplateArgumentHasher.h | 34 ++
clang/test/Modules/cxx-templates.cpp | 8 +-
.../Modules/recursive-instantiations.cppm | 40 ++
.../test/OpenMP/target_parallel_ast_print.cpp | 4 -
clang/test/OpenMP/target_teams_ast_print.cpp | 4 -
clang/test/OpenMP/task_ast_print.cpp | 4 -
clang/test/OpenMP/teams_ast_print.cpp | 4 -
24 files changed, 616 insertions(+), 287 deletions(-)
create mode 100644 clang/lib/Serialization/TemplateArgumentHasher.cpp
create mode 100644 clang/lib/Serialization/TemplateArgumentHasher.h
create mode 100644 clang/test/Modules/recursive-instantiations.cppm
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 7d707ed45cf5f6..336340e6dc6641 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -262,9 +262,6 @@ class TemplateArgumentList final
TemplateArgumentList(const TemplateArgumentList &) = delete;
TemplateArgumentList &operator=(const TemplateArgumentList &) = delete;
- /// Create hash for the given arguments.
- static unsigned ComputeODRHash(ArrayRef<TemplateArgument> Args);
-
/// Create a new template argument list that copies the given set of
/// template arguments.
static TemplateArgumentList *CreateCopy(ASTContext &Context,
@@ -738,25 +735,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
}
void anchor() override;
- struct LazySpecializationInfo {
- GlobalDeclID DeclID = GlobalDeclID();
- unsigned ODRHash = ~0U;
- bool IsPartial = false;
- LazySpecializationInfo(GlobalDeclID ID, unsigned Hash = ~0U,
- bool Partial = false)
- : DeclID(ID), ODRHash(Hash), IsPartial(Partial) {}
- LazySpecializationInfo() {}
- bool operator<(const LazySpecializationInfo &Other) const {
- return DeclID < Other.DeclID;
- }
- bool operator==(const LazySpecializationInfo &Other) const {
- assert((DeclID != Other.DeclID || ODRHash == Other.ODRHash) &&
- "Hashes differ!");
- assert((DeclID != Other.DeclID || IsPartial == Other.IsPartial) &&
- "Both must be the same kinds!");
- return DeclID == Other.DeclID;
- }
- };
protected:
template <typename EntryType> struct SpecEntryTraits {
@@ -800,16 +778,20 @@ class RedeclarableTemplateDecl : public TemplateDecl,
void loadLazySpecializationsImpl(bool OnlyPartial = false) const;
- void loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
+ bool loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
TemplateParameterList *TPL = nullptr) const;
- Decl *loadLazySpecializationImpl(LazySpecializationInfo &LazySpecInfo) 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);
diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h
index 5f4f9a9a8d681e..9f968ba05b4466 100644
--- a/clang/include/clang/AST/ExternalASTSource.h
+++ b/clang/include/clang/AST/ExternalASTSource.h
@@ -155,11 +155,15 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
/// Load all the external specializations for the Decl \param D if \param
/// OnlyPartial is false. Otherwise, load all the external **partial**
/// specializations for the \param D.
- virtual void LoadExternalSpecializations(const Decl *D, bool OnlyPartial);
+ ///
+ /// 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.
- virtual void
+ ///
+ /// Return true if any new specializations get loaded. Return false otherwise.
+ virtual bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs);
diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
index 78bbbaf2d7b5c6..0c92c52854c9e7 100644
--- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -97,9 +97,9 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;
- void LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
+ bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
- void
+ bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) override;
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index cb3ed6c1ecbb7c..b045c4f235cef0 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -737,6 +737,8 @@ enum ASTRecordTypes {
/// Record code for updated specialization
UPDATE_SPECIALIZATION = 73,
+
+ CXX_ADDED_TEMPLATE_SPECIALIZATION = 74,
};
/// Record types used within a source manager block.
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 6306d4f08e81fa..12f08386e2329d 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2098,9 +2098,9 @@ class ASTReader
unsigned BlockID,
uint64_t *StartOfBlockOffset = nullptr);
- void LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
+ bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
- void
+ bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) override;
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index a73af9c7785320..7fc0f02ce0a934 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -362,63 +362,30 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
OnlyPartial);
return;
-
- // Grab the most recent declaration to ensure we've loaded any lazy
- // redeclarations of this template.
- CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
- if (auto *Specs = CommonBasePtr->LazySpecializations) {
- if (!OnlyPartial)
- CommonBasePtr->LazySpecializations = nullptr;
- unsigned N = Specs[0].DeclID.getRawValue();
- for (unsigned I = 0; I != N; ++I) {
- // Skip over already loaded specializations.
- if (!Specs[I + 1].ODRHash)
- continue;
- if (!OnlyPartial || Specs[I + 1].IsPartial)
- (void)loadLazySpecializationImpl(Specs[I + 1]);
- }
- }
-}
-
-Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl(
- LazySpecializationInfo &LazySpecInfo) const {
- llvm_unreachable("We don't use LazySpecializationInfo any more");
-
- GlobalDeclID ID = LazySpecInfo.DeclID;
- assert(ID.isValid() && "Loading already loaded specialization!");
- // Note that we loaded the specialization.
- LazySpecInfo.DeclID = GlobalDeclID();
- LazySpecInfo.ODRHash = LazySpecInfo.IsPartial = 0;
- return getASTContext().getExternalSource()->GetExternalDecl(ID);
}
-void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
+bool RedeclarableTemplateDecl::loadLazySpecializationsImpl(
ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const {
auto *ExternalSource = getASTContext().getExternalSource();
if (!ExternalSource)
- return;
+ return false;
- ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), Args);
- return;
+ // 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);
- CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
- if (auto *Specs = CommonBasePtr->LazySpecializations) {
- unsigned Hash = TemplateArgumentList::ComputeODRHash(Args);
- unsigned N = Specs[0].DeclID.getRawValue();
- for (unsigned I = 0; I != N; ++I)
- if (Specs[I + 1].ODRHash && Specs[I + 1].ODRHash == Hash)
- (void)loadLazySpecializationImpl(Specs[I + 1]);
- }
+ return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
+ Args);
}
-template<class EntryType, typename... ProfileArguments>
+template <class EntryType, typename... ProfileArguments>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
-RedeclarableTemplateDecl::findSpecializationImpl(
+RedeclarableTemplateDecl::findSpecializationLocally(
llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
- ProfileArguments&&... ProfileArgs) {
- using SETraits = SpecEntryTraits<EntryType>;
-
- loadLazySpecializationsImpl(std::forward<ProfileArguments>(ProfileArgs)...);
+ ProfileArguments &&...ProfileArgs) {
+ using SETraits = RedeclarableTemplateDecl::SpecEntryTraits<EntryType>;
llvm::FoldingSetNodeID ID;
EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
@@ -427,6 +394,24 @@ RedeclarableTemplateDecl::findSpecializationImpl(
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,
@@ -955,14 +940,6 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
return new (Mem) TemplateArgumentList(Args);
}
-unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) {
- ODRHash Hasher;
- for (TemplateArgument TA : Args)
- Hasher.AddTemplateArgument(TA);
-
- return Hasher.CalculateHash();
-}
-
FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index 122014bfeb2321..0eeb549d8cabf3 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -98,10 +98,14 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
return false;
}
-void ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) {}
+bool ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) {
+ return false;
+}
-void ExternalASTSource::LoadExternalSpecializations(
- const Decl *D, ArrayRef<TemplateArgument>) {}
+bool ExternalASTSource::LoadExternalSpecializations(
+ const Decl *D, ArrayRef<TemplateArgument>) {
+ return false;
+}
void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {}
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index a8a3a5200d61ed..c73570e405ab68 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -819,16 +819,6 @@ void ODRHash::AddDecl(const Decl *D) {
AddDeclarationName(ND->getDeclName());
- 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);
- }
-
// 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).
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index f39463712ce81f..54944267b4868a 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -115,16 +115,21 @@ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
return AnyDeclsFound;
}
-void MultiplexExternalSemaSource::LoadExternalSpecializations(
+bool MultiplexExternalSemaSource::LoadExternalSpecializations(
const Decl *D, bool OnlyPartial) {
+ bool Loaded = false;
for (size_t i = 0; i < Sources.size(); ++i)
- Sources[i]->LoadExternalSpecializations(D, OnlyPartial);
+ Loaded |= Sources[i]->LoadExternalSpecializations(D, OnlyPartial);
+ return Loaded;
}
-void MultiplexExternalSemaSource::LoadExternalSpecializations(
+bool MultiplexExternalSemaSource::LoadExternalSpecializations(
const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) {
+ bool AnyNewSpecsLoaded = false;
for (size_t i = 0; i < Sources.size(); ++i)
- Sources[i]->LoadExternalSpecializations(D, TemplateArgs);
+ AnyNewSpecsLoaded |=
+ Sources[i]->LoadExternalSpecializations(D, TemplateArgs);
+ return AnyNewSpecsLoaded;
}
void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){
diff --git a/clang/lib/Serialization/ASTCommon.h b/clang/lib/Serialization/ASTCommon.h
index 2a765eafe08951..7c9ec884ea049d 100644
--- a/clang/lib/Serialization/ASTCommon.h
+++ b/clang/lib/Serialization/ASTCommon.h
@@ -24,7 +24,6 @@ namespace serialization {
enum DeclUpdateKind {
UPD_CXX_ADDED_IMPLICIT_MEMBER,
- UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
UPD_CXX_ADDED_FUNCTION_DEFINITION,
UPD_CXX_ADDED_VAR_DEFINITION,
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 75d81a25dd3ac3..f6f7969314bf54 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -12,6 +12,7 @@
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
+#include "TemplateArgumentHasher.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -3542,7 +3543,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
break;
}
- case UPDATE_SPECIALIZATION: {
+ case CXX_ADDED_TEMPLATE_SPECIALIZATION: {
unsigned Idx = 0;
GlobalDeclID ID = ReadDeclID(F, Record, Idx);
auto *Data = (const unsigned char *)Blob.data();
@@ -7747,8 +7748,14 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
}
}
- if (Template)
- Template->loadLazySpecializationsImpl(Args);
+ if (Template) {
+ // For partitial specialization, load all the specializations for safety.
+ if (isa<ClassTemplatePartialSpecializationDecl,
+ VarTemplatePartialSpecializationDecl>(D))
+ Template->loadLazySpecializationsImpl();
+ else
+ Template->loadLazySpecializationsImpl(Args);
+ }
}
CXXCtorInitializer **
@@ -8129,12 +8136,12 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
return ReadStmtFromStream(*Loc.F);
}
-void ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
+bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
assert(D);
auto It = SpecializationsLookups.find(D);
if (It == SpecializationsLookups.end())
- return;
+ return false;
// Get Decl may violate the iterator from SpecializationsLookups so we store
// the DeclIDs in ahead.
@@ -8146,29 +8153,43 @@ void ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
if (!OnlyPartial)
SpecializationsLookups.erase(It);
+ bool NewSpecsFound = false;
Deserializing LookupResults(this);
for (auto &Info : Infos)
- if (!OnlyPartial || Info.IsPartial)
+ if (!OnlyPartial || Info.IsPartial) {
+ if (GetExistingDecl(Info.ID))
+ continue;
+ NewSpecsFound = true;
GetDecl(Info.ID);
+ }
+
+ return NewSpecsFound;
}
-void ASTReader::LoadExternalSpecializations(
+bool ASTReader::LoadExternalSpecializations(
const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) {
assert(D);
auto It = SpecializationsLookups.find(D);
if (It == SpecializationsLookups.end())
- return;
+ return false;
Deserializing LookupResults(this);
- auto HashValue = TemplateArgumentList::ComputeODRHash(TemplateArgs);
+ auto HashValue = StableHashForTemplateArguments(TemplateArgs);
// Get Decl may violate the iterator from SpecializationsLookups
llvm::SmallVector<serialization::reader::LazySpecializationInfo, 8> Infos =
It->second.Table.find(HashValue);
- for (auto &Info : Infos)
+ bool NewSpecsFound = false;
+ for (auto &Info : Infos) {
+ if (GetExistingDecl(Info.ID))
+ continue;
+ NewSpecsFound = true;
GetDecl(Info.ID);
+ }
+
+ return NewSpecsFound;
}
void ASTReader::FindExternalLexicalDecls(
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 87c491a977ffeb..9ac712d8625db8 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -187,21 +187,6 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
std::string readString() { return Record.readString(); }
- using LazySpecializationInfo =
- RedeclarableTemplateDecl::LazySpecializationInfo;
-
- LazySpecializationInfo ReadLazySpecializationInfo() {
- GlobalDeclID ID = readDeclID();
- unsigned Hash = Record.readInt();
- bool IsPartial = Record.readInt();
- return LazySpecializationInfo(ID, Hash, IsPartial);
- }
-
- void readDeclIDList(SmallVectorImpl<LazySpecializationInfo> &IDs) {
- for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I)
- IDs.push_back(ReadLazySpecializationInfo());
- }
-
Decl *readDecl() { return Record.readDecl(); }
template <typename T> T *readDeclAs() { return Record.readDeclAs<T>(); }
@@ -294,30 +279,6 @@ 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<LazySpecializationInfo> &IDs) {
- if (IDs.empty())
- return;
-
- // FIXME: We should avoid this pattern of getting the ASTContext.
- ASTContext &C = D->getASTContext();
-
- auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations;
-
- if (auto &Old = LazySpecializations) {
- IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].DeclID.getRawValue());
- llvm::sort(IDs);
- IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
- }
- auto *Result = new (C)
- RedeclarableTemplateDecl::LazySpecializationInfo[1 + IDs.size()];
- Result->DeclID = 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(...);
@@ -348,9 +309,7 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
void ReadFunctionDefinition(FunctionDecl *FD);
void Visit(Decl *D);
- void UpdateDecl(
- Decl *D,
- SmallVectorImpl<RedeclarableTemplateDecl::LazySpecializationInfo> &);
+ void UpdateDecl(Decl *D);
static void setNextObjCCategory(ObjCCategoryDecl *Cat,
ObjCCategoryDecl *Next) {
@@ -2479,9 +2438,6 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
- SmallVector<LazySpecializationInfo, 32> SpecIDs;
- readDeclIDList(SpecIDs);
- ASTDeclReader::AddLazySpecializations(D, SpecIDs);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor);
}
@@ -2508,9 +2464,6 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
- SmallVector<LazySpecializationInfo, 32> SpecIDs;
- readDeclIDList(SpecIDs);
- ASTDeclReader::AddLazySpecializations(D, SpecIDs);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor);
}
}
@@ -2610,9 +2563,6 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
- SmallVector<LazySpecializationInfo, 32> SpecIDs;
- readDeclIDList(SpecIDs);
- ASTDeclReader::AddLazySpecializations(D, SpecIDs);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor);
}
}
@@ -4313,10 +4263,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
- using LazySpecializationInfo =
- RedeclarableTemplateDecl::LazySpecializationInfo;
- llvm::SmallVector<LazySpecializationInfo, 8> PendingLazySpecializationIDs;
-
if (UpdI != DeclUpdateOffsets.end()) {
auto UpdateOffsets = std::move(UpdI->second);
DeclUpdateOffsets.erase(UpdI);
@@ -4353,7 +4299,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID,
SourceLocation());
- Reader.UpdateDecl(D, PendingLazySpecializationIDs);
+ Reader.UpdateDecl(D);
// We might have made this declaration interesting. If so, remember that
// we need to hand it off to the consumer.
@@ -4363,19 +4309,6 @@ 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);
@@ -4602,9 +4535,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) {
}
}
-void ASTDeclReader::UpdateDecl(
- Decl *D,
- SmallVectorImpl<LazySpecializationInfo> &PendingLazySpecializationIDs) {
+void ASTDeclReader::UpdateDecl(Decl *D) {
while (Record.getIdx() < Record.size()) {
switch ((DeclUpdateKind)Record.readInt()) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
@@ -4615,11 +4546,6 @@ void ASTDeclReader::UpdateDecl(
break;
}
- case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
- // It will be added to the template's lazy specialization set.
- PendingLazySpecializationIDs.push_back(ReadLazySpecializationInfo());
- break;
-
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
auto *Anon = readDeclAs<NamespaceDecl>();
diff --git a/clang/lib/Serialization/ASTReaderInternals.h b/clang/lib/Serialization/ASTReaderInternals.h
index b921d8d174c3a2..840ddf81e0201a 100644
--- a/clang/lib/Serialization/ASTReaderInternals.h
+++ b/clang/lib/Serialization/ASTReaderInternals.h
@@ -125,11 +125,10 @@ struct LazySpecializationInfo {
// Whether or not this specialization is partial.
bool IsPartial;
- bool operator==(const LazySpecializationInfo &Other) {
+ bool operator==(const LazySpecializationInfo &Other) const {
assert(ID != Other.ID || IsPartial == Other.IsPartial);
return ID == Other.ID;
}
-
// Records the size record in OnDiskHashTable.
// sizeof() may return 8 due to align requirements.
static constexpr unsigned Length = sizeof(DeclID) + sizeof(IsPartial);
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index adfe9fc8b369d6..d4898b3dac3f52 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -13,6 +13,7 @@
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
#include "MultiOnDiskHashTable.h"
+#include "TemplateArgumentHasher.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTUnresolvedSet.h"
#include "clang/AST/AbstractTypeWriter.h"
@@ -4125,7 +4126,7 @@ class LazySpecializationInfoLookupTrait {
explicit LazySpecializationInfoLookupTrait(ASTWriter &Writer)
: Writer(Writer) {}
- template <typename Col> data_type getData(Col &&C) {
+ template <typename Col, typename Col2> data_type getData(Col &&C, Col2 &ExistingInfo) {
unsigned Start = Specs.size();
for (auto *D : C) {
bool IsPartial = isa<ClassTemplatePartialSpecializationDecl,
@@ -4135,6 +4136,8 @@ class LazySpecializationInfoLookupTrait {
Specs.push_back({GlobalDeclID(Writer.GetDeclRef(ND).getRawValue()),
IsPartial});
}
+ for (const serialization::reader::LazySpecializationInfo &Info : ExistingInfo)
+ Specs.push_back(Info);
return std::make_pair(Start, Specs.size());
}
@@ -4203,7 +4206,7 @@ unsigned CalculateODRHashForSpecs(const Decl *Spec) {
else
llvm_unreachable("New Specialization Kind?");
- return TemplateArgumentList::ComputeODRHash(Args);
+ return StableHashForTemplateArguments(Args);
}
} // namespace
@@ -4234,11 +4237,23 @@ void ASTWriter::GenerateSpecializationInfoLookupTable(
Iter->second.push_back(cast<NamedDecl>(Specialization));
}
- for (auto Iter : SpecializationMaps)
- Generator.insert(Iter.first, Trait.getData(Iter.second), Trait);
-
auto *Lookups =
Chain ? Chain->getLoadedSpecializationsLookupTables(D) : 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);
}
@@ -5921,7 +5936,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
void ASTWriter::WriteSpecializationsUpdates() {
auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
- Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_SPECIALIZATION));
+ Abv->Add(llvm::BitCodeAbbrevOp(CXX_ADDED_TEMPLATE_SPECIALIZATION));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
auto UpdateSpecializationAbbrev = Stream.EmitAbbrev(std::move(Abv));
@@ -5934,7 +5949,8 @@ void ASTWriter::WriteSpecializationsUpdates() {
LookupTable);
// Write the lookup table
- RecordData::value_type Record[] = {UPDATE_SPECIALIZATION, getDeclID(D).getRawValue()};
+ RecordData::value_type Record[] = {CXX_ADDED_TEMPLATE_SPECIALIZATION,
+ getDeclID(D).getRawValue()};
Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable);
}
}
@@ -5972,25 +5988,6 @@ void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context,
assert(Update.getDecl() && "no decl to add?");
Record.AddDeclRef(Update.getDecl());
break;
- case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: {
- const Decl *Spec = Update.getDecl();
- assert(Spec && "no decl to add?");
- Record.AddDeclRef(Spec);
- ArrayRef<TemplateArgument> Args;
- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Spec))
- Args = CTSD->getTemplateArgs().asArray();
- else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Spec))
- Args = VTSD->getTemplateArgs().asArray();
- else if (auto *FD = dyn_cast<FunctionDecl>(Spec))
- Args = FD->getTemplateSpecializationArgs()->asArray();
- assert(Args.size());
- Record.push_back(TemplateArgumentList::ComputeODRHash(Args));
- bool IsPartialSpecialization =
- isa<ClassTemplatePartialSpecializationDecl>(Spec) ||
- isa<VarTemplatePartialSpecializationDecl>(Spec);
- Record.push_back(IsPartialSpecialization);
- break;
- }
case UPD_CXX_ADDED_FUNCTION_DEFINITION:
case UPD_CXX_ADDED_VAR_DEFINITION:
break;
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 14c2f23700e8c3..78c4f3bd62c33f 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -215,24 +215,8 @@ namespace clang {
llvm::MapVector<ModuleFile *, const Decl *> Firsts;
CollectFirstDeclFromEachModule(D, /*IncludeLocal*/ true, Firsts);
- for (const auto &F : Firsts) {
+ for (const auto &F : Firsts)
SpecsInMap.push_back(F.second);
-
- Record.AddDeclRef(F.second);
- ArrayRef<TemplateArgument> Args;
- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
- Args = CTSD->getTemplateArgs().asArray();
- else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
- Args = VTSD->getTemplateArgs().asArray();
- else if (auto *FD = dyn_cast<FunctionDecl>(D))
- Args = FD->getTemplateSpecializationArgs()->asArray();
- assert(Args.size());
- Record.push_back(TemplateArgumentList::ComputeODRHash(Args));
- bool IsPartialSpecialization =
- isa<ClassTemplatePartialSpecializationDecl>(D) ||
- isa<VarTemplatePartialSpecializationDecl>(D);
- Record.push_back(IsPartialSpecialization);
- }
}
/// Get the specialization decl from an entry in the specialization list.
@@ -259,23 +243,12 @@ namespace clang {
// If we have any lazy specializations, and the external AST source is
// our chained AST reader, we can just write out the DeclIDs. Otherwise,
// we need to resolve them to actual declarations.
- if (Writer.Chain != Record.getASTContext().getExternalSource() &&
- Common->LazySpecializations) {
+ if (Writer.Chain != Writer.Context->getExternalSource() && Writer.Chain &&
+ Writer.Chain->getLoadedSpecializationsLookupTables(D)) {
D->LoadLazySpecializations();
- assert(!Common->LazySpecializations);
+ assert(!Writer.Chain->getLoadedSpecializationsLookupTables(D));
}
- using LazySpecializationInfo =
- RedeclarableTemplateDecl::LazySpecializationInfo;
- ArrayRef<LazySpecializationInfo> LazySpecializations;
- if (auto *LS = Common->LazySpecializations)
- LazySpecializations =
- llvm::ArrayRef(LS + 1, LS[0].DeclID.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;
@@ -291,21 +264,6 @@ namespace clang {
AddFirstSpecializationDeclFromEachModule(D, SpecsInOnDiskMap);
}
- // We don't need to insert LazySpecializations to SpecsInOnDiskMap,
- // since we'll handle that in GenerateSpecializationInfoLookupTable.
- for (auto &SpecInfo : LazySpecializations) {
- Record.push_back(SpecInfo.DeclID.getRawValue());
- Record.push_back(SpecInfo.ODRHash);
- Record.push_back(SpecInfo.IsPartial);
- }
-
- // Update the size entry we added earlier. We linerized the
- // LazySpecializationInfo members and we need to adjust the size as we
- // will read them always together.
- assert((Record.size() - I - 1) % 3 == 0 &&
- "Must be divisible by LazySpecializationInfo count!");
- Record[I] = (Record.size() - I - 1) / 3;
-
Record.AddOffset(
Writer.WriteSpecializationInfoLookupTable(D, SpecsInOnDiskMap));
}
@@ -328,9 +286,6 @@ namespace clang {
if (Writer.getFirstLocalDecl(Specialization) != Specialization)
return;
- Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate(
- UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization));
-
Writer.SpecializationsUpdates[cast<NamedDecl>(Template)].push_back(
cast<NamedDecl>(Specialization));
}
diff --git a/clang/lib/Serialization/CMakeLists.txt b/clang/lib/Serialization/CMakeLists.txt
index 99c47c15a2f479..b1fc0345047f24 100644
--- a/clang/lib/Serialization/CMakeLists.txt
+++ b/clang/lib/Serialization/CMakeLists.txt
@@ -23,6 +23,7 @@ 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
new file mode 100644
index 00000000000000..598f098f526d0f
--- /dev/null
+++ b/clang/lib/Serialization/TemplateArgumentHasher.cpp
@@ -0,0 +1,409 @@
+//===- TemplateArgumentHasher.cpp - Hash Template Arguments -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TemplateArgumentHasher.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/FoldingSet.h"
+
+using namespace clang;
+
+namespace {
+
+class TemplateArgumentHasher {
+ // If we bail out during the process of calculating hash values for
+ // template arguments for any reason. We're allowed to do it since
+ // TemplateArgumentHasher are only required to give the same hash value
+ // for the same template arguments, but not required to give different
+ // hash value for different template arguments.
+ //
+ // So in the worst case, it is still a valid implementation to give all
+ // inputs the same BailedOutValue as output.
+ bool BailedOut = false;
+ static constexpr unsigned BailedOutValue = 0x12345678;
+
+ llvm::FoldingSetNodeID ID;
+
+public:
+ TemplateArgumentHasher() = default;
+
+ void AddTemplateArgument(TemplateArgument TA);
+
+ void AddInteger(unsigned V) { ID.AddInteger(V); }
+
+ unsigned getValue() {
+ if (BailedOut)
+ return BailedOutValue;
+
+ return ID.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 differ from one compiler invocation to another.
+ // It may be difficult to handle such cases. Bail out simply.
+
+ if (Kind == APValue::LValue || Kind == APValue::MemberPointer) {
+ BailedOut = true;
+ return;
+ }
+
+ Value.Profile(ID);
+}
+
+void TemplateArgumentHasher::AddTemplateName(TemplateName Name) {
+ switch (Name.getKind()) {
+ case TemplateName::Template:
+ AddDecl(Name.getAsTemplateDecl());
+ break;
+ case TemplateName::QualifiedTemplate: {
+ QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName();
+ AddTemplateName(QTN->getUnderlyingTemplate());
+ break;
+ }
+ case TemplateName::OverloadedTemplate:
+ case TemplateName::AssumedTemplate:
+ case TemplateName::DependentTemplate:
+ case TemplateName::SubstTemplateTemplateParm:
+ case TemplateName::SubstTemplateTemplateParmPack:
+ BailedOut = true;
+ break;
+ case TemplateName::UsingTemplate: {
+ UsingShadowDecl *USD = Name.getAsUsingShadowDecl();
+ if (USD)
+ AddDecl(USD->getTargetDecl());
+ else
+ BailedOut = true;
+ break;
+ }
+ 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
new file mode 100644
index 00000000000000..f23f1318afbbf4
--- /dev/null
+++ b/clang/lib/Serialization/TemplateArgumentHasher.h
@@ -0,0 +1,34 @@
+//===- TemplateArgumentHasher.h - Hash Template Arguments -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/TemplateBase.h"
+
+namespace clang {
+namespace serialization {
+
+/// Calculate a stable hash value for template arguments. We guarantee that
+/// the same template arguments must have the same hashed values. But we don't
+/// guarantee that the template arguments with the same hashed value are the
+/// same template arguments.
+///
+/// ODR hashing may not be the best mechanism to hash the template
+/// arguments. ODR hashing is (or perhaps, should be) about determining whether
+/// two things are spelled the same way and have the same meaning (as required
+/// by the C++ ODR), whereas what we want here is whether they have the same
+/// meaning regardless of spelling. Maybe we can get away with reusing ODR
+/// hashing anyway, on the basis that any canonical, non-dependent template
+/// argument should have the same (invented) spelling in every translation
+/// unit, but it is not sure that's true in all cases. There may still be cases
+/// where the canonical type includes some aspect of "whatever we saw first",
+/// in which case the ODR hash can differ across translation units for
+/// non-dependent, canonical template arguments that are spelled differently
+/// but have the same meaning. But it is not easy to raise examples.
+unsigned StableHashForTemplateArguments(llvm::ArrayRef<TemplateArgument> Args);
+
+} // namespace serialization
+} // namespace clang
diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp
index e10ba7c2ac3ef2..b7d5741e69af61 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -251,7 +251,7 @@ namespace Std {
// CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in cxx_templates_common SomeTemplate
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
-// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]'
+// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
// CHECK-DUMP-NEXT: DefinitionData
// CHECK-DUMP-NEXT: DefaultConstructor
@@ -260,9 +260,9 @@ namespace Std {
// CHECK-DUMP-NEXT: CopyAssignment
// CHECK-DUMP-NEXT: MoveAssignment
// CHECK-DUMP-NEXT: Destructor
-// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]'
-// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]'
+// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
+// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
// CHECK-DUMP-NEXT: DefinitionData
// CHECK-DUMP-NEXT: DefaultConstructor
@@ -271,4 +271,4 @@ namespace Std {
// CHECK-DUMP-NEXT: CopyAssignment
// CHECK-DUMP-NEXT: MoveAssignment
// CHECK-DUMP-NEXT: Destructor
-// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]'
+// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]'
diff --git a/clang/test/Modules/recursive-instantiations.cppm b/clang/test/Modules/recursive-instantiations.cppm
new file mode 100644
index 00000000000000..d5854b0e647e37
--- /dev/null
+++ b/clang/test/Modules/recursive-instantiations.cppm
@@ -0,0 +1,40 @@
+// 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 7e27ac7b92ca4a..3ee98bc525c1bd 100644
--- a/clang/test/OpenMP/target_parallel_ast_print.cpp
+++ b/clang/test/OpenMP/target_parallel_ast_print.cpp
@@ -38,10 +38,6 @@ 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 8338f2a68f9228..cc47ae92efac0f 100644
--- a/clang/test/OpenMP/target_teams_ast_print.cpp
+++ b/clang/test/OpenMP/target_teams_ast_print.cpp
@@ -40,10 +40,6 @@ 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 2a6b8908a1e2dc..30fb7ab75cc87a 100644
--- a/clang/test/OpenMP/task_ast_print.cpp
+++ b/clang/test/OpenMP/task_ast_print.cpp
@@ -87,10 +87,6 @@ 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 0087f71ac9f742..597a9b2bdbdc5d 100644
--- a/clang/test/OpenMP/teams_ast_print.cpp
+++ b/clang/test/OpenMP/teams_ast_print.cpp
@@ -27,10 +27,6 @@ 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) {
>From 4d5b9585684f008c25dc88b2b3fa55509b9627e4 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Fri, 8 Nov 2024 16:49:05 +0800
Subject: [PATCH 2/2] Split partial specializations from the lookup table
---
clang/include/clang/AST/DeclTemplate.h | 7 --
.../include/clang/Serialization/ASTBitCodes.h | 11 +-
clang/include/clang/Serialization/ASTReader.h | 30 +++--
clang/include/clang/Serialization/ASTWriter.h | 9 +-
clang/lib/Serialization/ASTReader.cpp | 111 +++++++++++++-----
clang/lib/Serialization/ASTReaderDecl.cpp | 29 +++--
clang/lib/Serialization/ASTReaderInternals.h | 43 +------
clang/lib/Serialization/ASTWriter.cpp | 55 +++++----
clang/lib/Serialization/ASTWriterDecl.cpp | 63 +++++++---
9 files changed, 216 insertions(+), 142 deletions(-)
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 336340e6dc6641..dd92d40b804232 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -806,13 +806,6 @@ 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.
- LazySpecializationInfo *LazySpecializations = nullptr;
};
/// Pointer to the common data shared by all declarations of this
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index b045c4f235cef0..e2a165055a442f 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -737,8 +737,10 @@ enum ASTRecordTypes {
/// 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.
@@ -1505,11 +1507,14 @@ enum DeclCode {
/// A HLSLBufferDecl record.
DECL_HLSL_BUFFER,
+ /// An ImplicitConceptSpecializationDecl record.
+ DECL_IMPLICIT_CONCEPT_SPECIALIZATION,
+
// A decls specilization record.
DECL_SPECIALIZATIONS,
- /// An ImplicitConceptSpecializationDecl record.
- DECL_IMPLICIT_CONCEPT_SPECIALIZATION,
+ // 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 12f08386e2329d..fb750175baf2c9 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -635,10 +635,19 @@ 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.
- llvm::DenseMap<const Decl *,
- serialization::reader::LazySpecializationInfoLookupTable>
- SpecializationsLookups;
+ 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
@@ -655,8 +664,10 @@ class ASTReader
llvm::DenseMap<GlobalDeclID, DeclContextVisibleUpdates> PendingVisibleUpdates;
using SpecializationsUpdate = SmallVector<UpdateData, 1>;
- llvm::DenseMap<GlobalDeclID, SpecializationsUpdate>
- PendingSpecializationsUpdates;
+ 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.
@@ -691,9 +702,9 @@ class ASTReader
uint64_t Offset, GlobalDeclID ID);
bool ReadSpecializations(ModuleFile &M, llvm::BitstreamCursor &Cursor,
- uint64_t Offset, Decl *D);
+ uint64_t Offset, Decl *D, bool IsPartial);
void AddSpecializations(const Decl *D, const unsigned char *Data,
- ModuleFile &M);
+ ModuleFile &M, bool IsPartial);
/// A vector containing identifiers that have already been
/// loaded.
@@ -1439,7 +1450,10 @@ class ASTReader
/// Get the loaded specializations lookup tables for \p D,
/// if any.
serialization::reader::LazySpecializationInfoLookupTable *
- getLoadedSpecializationsLookupTables(const Decl *D);
+ getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial);
+
+ /// If we have any unloaded specialization for \p D
+ bool haveUnloadedSpecializations(const Decl *D) const;
private:
struct ImportedModule {
diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h
index 9da22f96130a8b..cdbcc96b9a470e 100644
--- a/clang/include/clang/Serialization/ASTWriter.h
+++ b/clang/include/clang/Serialization/ASTWriter.h
@@ -428,6 +428,7 @@ class ASTWriter : public ASTDeserializationListener,
using SpecializationUpdateMap =
llvm::MapVector<const NamedDecl *, SmallVector<const Decl *>>;
SpecializationUpdateMap SpecializationsUpdates;
+ SpecializationUpdateMap PartialSpecializationsUpdates;
using FirstLatestDeclMap = llvm::DenseMap<Decl *, Decl *>;
@@ -580,9 +581,10 @@ class ASTWriter : public ASTDeserializationListener,
void GenerateSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
- llvm::SmallVectorImpl<char> &LookupTable);
+ llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial);
uint64_t WriteSpecializationInfoLookupTable(
- const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations);
+ 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,
@@ -598,7 +600,7 @@ class ASTWriter : public ASTDeserializationListener,
void WriteDeclAndTypes(ASTContext &Context);
void PrepareWritingSpecialDecls(Sema &SemaRef);
void WriteSpecialDeclRecords(Sema &SemaRef);
- void WriteSpecializationsUpdates();
+ void WriteSpecializationsUpdates(bool IsPartial);
void WriteDeclUpdatesBlocks(ASTContext &Context,
RecordDataImpl &OffsetsRecord);
void WriteDeclContextVisibleUpdate(ASTContext &Context,
@@ -629,6 +631,7 @@ class ASTWriter : public ASTDeserializationListener,
unsigned DeclObjCIvarAbbrev = 0;
unsigned DeclCXXMethodAbbrev = 0;
unsigned DeclSpecializationsAbbrev = 0;
+ unsigned DeclPartialSpecializationsAbbrev = 0;
unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0;
unsigned DeclTemplateCXXMethodAbbrev = 0;
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index f6f7969314bf54..ce6c879127918d 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1311,13 +1311,11 @@ void LazySpecializationInfoLookupTrait::ReadDataInto(internal_key_type,
using namespace llvm::support;
for (unsigned NumDecls =
- DataLen / serialization::reader::LazySpecializationInfo::Length;
+ DataLen / sizeof(serialization::reader::LazySpecializationInfo);
NumDecls; --NumDecls) {
LocalDeclID LocalID =
LocalDeclID::get(Reader, F, endian::readNext<DeclID, llvm::endianness::little, unaligned>(d));
- const bool IsPartial =
- endian::readNext<bool, llvm::endianness::little, unaligned>(d);
- Val.insert({Reader.getGlobalDeclID(F, LocalID), IsPartial});
+ Val.insert(Reader.getGlobalDeclID(F, LocalID));
}
}
@@ -1410,14 +1408,16 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M,
}
void ASTReader::AddSpecializations(const Decl *D, const unsigned char *Data,
- ModuleFile &M) {
+ ModuleFile &M, bool IsPartial) {
D = D->getCanonicalDecl();
- SpecializationsLookups[D].Table.add(
- &M, Data, reader::LazySpecializationInfoLookupTrait(*this, M));
+ 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) {
+ uint64_t Offset, Decl *D, bool IsPartial) {
assert(Offset != 0);
SavedStreamPosition SavedPosition(Cursor);
@@ -1441,13 +1441,14 @@ bool ASTReader::ReadSpecializations(ModuleFile &M, BitstreamCursor &Cursor,
return true;
}
unsigned RecCode = MaybeRecCode.get();
- if (RecCode != DECL_SPECIALIZATIONS) {
+ 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);
+ AddSpecializations(D, Data, M, IsPartial);
return false;
}
@@ -3556,6 +3557,19 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
break;
}
+ case CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION: {
+ unsigned Idx = 0;
+ GlobalDeclID ID = ReadDeclID(F, Record, Idx);
+ auto *Data = (const unsigned char *)Blob.data();
+ PendingPartialSpecializationsUpdates[ID].push_back(UpdateData{&F, Data});
+ // If we've already loaded the decl, perform the updates when we finish
+ // loading this block.
+ if (Decl *D = GetExistingDecl(ID))
+ PendingUpdateRecords.push_back(
+ PendingUpdateRecord(ID, D, /*JustLoaded=*/false));
+ break;
+ }
+
case IDENTIFIER_TABLE:
F.IdentifierTableData =
reinterpret_cast<const unsigned char *>(Blob.data());
@@ -8136,11 +8150,12 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
return ReadStmtFromStream(*Loc.F);
}
-bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
+bool ASTReader::LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
+ const Decl *D) {
assert(D);
- auto It = SpecializationsLookups.find(D);
- if (It == SpecializationsLookups.end())
+ auto It = SpecLookups.find(D);
+ if (It == SpecLookups.end())
return false;
// Get Decl may violate the iterator from SpecializationsLookups so we store
@@ -8150,48 +8165,71 @@ bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
// Since we've loaded all the specializations, we can erase it from
// the lookup table.
- if (!OnlyPartial)
- SpecializationsLookups.erase(It);
+ SpecLookups.erase(It);
bool NewSpecsFound = false;
Deserializing LookupResults(this);
- for (auto &Info : Infos)
- if (!OnlyPartial || Info.IsPartial) {
- if (GetExistingDecl(Info.ID))
- continue;
- NewSpecsFound = true;
- GetDecl(Info.ID);
- }
+ for (auto &Info : Infos) {
+ if (GetExistingDecl(Info))
+ continue;
+ NewSpecsFound = true;
+ GetDecl(Info);
+ }
return NewSpecsFound;
}
-bool ASTReader::LoadExternalSpecializations(
- const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) {
+bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
assert(D);
- auto It = SpecializationsLookups.find(D);
- if (It == SpecializationsLookups.end())
+ 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 SpecializationsLookups
+ // 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.ID))
+ if (GetExistingDecl(Info))
continue;
NewSpecsFound = true;
- GetDecl(Info.ID);
+ 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) {
@@ -8372,10 +8410,19 @@ ASTReader::getLoadedLookupTables(DeclContext *Primary) const {
}
serialization::reader::LazySpecializationInfoLookupTable *
-ASTReader::getLoadedSpecializationsLookupTables(const Decl *D) {
+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());
- auto I = SpecializationsLookups.find(D);
- return I == SpecializationsLookups.end() ? nullptr : &I->second;
+ return (PartialSpecializationsLookups.find(D) !=
+ PartialSpecializationsLookups.end()) ||
+ (SpecializationsLookups.find(D) != SpecializationsLookups.end());
}
/// Under non-PCH compilation the consumer receives the objc methods
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 9ac712d8625db8..bd201e6cb14c11 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -304,7 +304,7 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
static void markIncompleteDeclChainImpl(...);
void ReadSpecializations(ModuleFile &M, Decl *D,
- llvm::BitstreamCursor &DeclsCursor);
+ llvm::BitstreamCursor &DeclsCursor, bool IsPartial);
void ReadFunctionDefinition(FunctionDecl *FD);
void Visit(Decl *D);
@@ -2393,9 +2393,11 @@ void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
}
void ASTDeclReader::ReadSpecializations(ModuleFile &M, Decl *D,
- llvm::BitstreamCursor &DeclsCursor) {
+ llvm::BitstreamCursor &DeclsCursor,
+ bool IsPartial) {
uint64_t Offset = ReadLocalOffset();
- bool Failed = Reader.ReadSpecializations(M, DeclsCursor, Offset, D);
+ bool Failed =
+ Reader.ReadSpecializations(M, DeclsCursor, Offset, D, IsPartial);
(void)Failed;
assert(!Failed);
}
@@ -2438,7 +2440,8 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
- ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor);
+ ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false);
+ ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true);
}
if (D->getTemplatedDecl()->TemplateOrInstantiation) {
@@ -2464,7 +2467,8 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
- ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor);
+ ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false);
+ ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true);
}
}
@@ -2563,7 +2567,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
- ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor);
+ ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false);
}
}
@@ -3854,6 +3858,7 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
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);
@@ -4341,7 +4346,17 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
PendingSpecializationsUpdates.erase(I);
for (const auto &Update : SpecializationUpdates)
- AddSpecializations(D, Update.Data, *Update.Mod);
+ 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);
}
}
diff --git a/clang/lib/Serialization/ASTReaderInternals.h b/clang/lib/Serialization/ASTReaderInternals.h
index 840ddf81e0201a..be0d22d1f4094f 100644
--- a/clang/lib/Serialization/ASTReaderInternals.h
+++ b/clang/lib/Serialization/ASTReaderInternals.h
@@ -119,20 +119,7 @@ struct DeclContextLookupTable {
MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> Table;
};
-struct LazySpecializationInfo {
- // The Decl ID for the specialization.
- GlobalDeclID ID;
- // Whether or not this specialization is partial.
- bool IsPartial;
-
- bool operator==(const LazySpecializationInfo &Other) const {
- assert(ID != Other.ID || IsPartial == Other.IsPartial);
- return ID == Other.ID;
- }
- // Records the size record in OnDiskHashTable.
- // sizeof() may return 8 due to align requirements.
- static constexpr unsigned Length = sizeof(DeclID) + sizeof(IsPartial);
-};
+using LazySpecializationInfo = GlobalDeclID;
/// Class that performs lookup to specialized decls.
class LazySpecializationInfoLookupTrait {
@@ -383,32 +370,4 @@ using HeaderFileInfoLookupTable =
} // namespace clang
-namespace llvm {
-// ID is unique in LazySpecializationInfo, it is redundant to calculate
-// IsPartial.
-template <>
-struct DenseMapInfo<clang::serialization::reader::LazySpecializationInfo> {
- using LazySpecializationInfo =
- clang::serialization::reader::LazySpecializationInfo;
- using Wrapped = DenseMapInfo<clang::serialization::DeclID>;
-
- static inline LazySpecializationInfo getEmptyKey() {
- return {(clang::GlobalDeclID)Wrapped::getEmptyKey(), false};
- }
-
- static inline LazySpecializationInfo getTombstoneKey() {
- return {(clang::GlobalDeclID)Wrapped::getTombstoneKey(), false};
- }
-
- static unsigned getHashValue(const LazySpecializationInfo &Key) {
- return Wrapped::getHashValue(Key.ID.getRawValue());
- }
-
- static bool isEqual(const LazySpecializationInfo &LHS,
- const LazySpecializationInfo &RHS) {
- return LHS.ID == RHS.ID;
- }
-};
-} // end namespace llvm
-
#endif // LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index d4898b3dac3f52..648096387578bd 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -4129,12 +4129,9 @@ class LazySpecializationInfoLookupTrait {
template <typename Col, typename Col2> data_type getData(Col &&C, Col2 &ExistingInfo) {
unsigned Start = Specs.size();
for (auto *D : C) {
- bool IsPartial = isa<ClassTemplatePartialSpecializationDecl,
- VarTemplatePartialSpecializationDecl>(D);
NamedDecl *ND = getDeclForLocalLookup(
Writer.getLangOpts(), const_cast<NamedDecl *>(D));
- Specs.push_back({GlobalDeclID(Writer.GetDeclRef(ND).getRawValue()),
- IsPartial});
+ Specs.push_back(GlobalDeclID(Writer.GetDeclRef(ND).getRawValue()));
}
for (const serialization::reader::LazySpecializationInfo &Info : ExistingInfo)
Specs.push_back(Info);
@@ -4167,7 +4164,7 @@ class LazySpecializationInfoLookupTrait {
data_type_ref Lookup) {
// 4 bytes for each slot.
unsigned KeyLen = 4;
- unsigned DataLen = serialization::reader::LazySpecializationInfo::Length *
+ unsigned DataLen = sizeof(serialization::reader::LazySpecializationInfo) *
(Lookup.second - Lookup.first);
return emitULEBKeyDataLength(KeyLen, DataLen, Out);
@@ -4188,8 +4185,7 @@ class LazySpecializationInfoLookupTrait {
uint64_t Start = Out.tell();
(void)Start;
for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) {
- LE.write<DeclID>(Specs[I].ID.getRawValue());
- LE.write<bool>(Specs[I].IsPartial);
+ LE.write<DeclID>(Specs[I].getRawValue());
}
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
@@ -4212,7 +4208,7 @@ unsigned CalculateODRHashForSpecs(const Decl *Spec) {
void ASTWriter::GenerateSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
- llvm::SmallVectorImpl<char> &LookupTable) {
+ llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial) {
assert(D->isFirstDecl());
// Create the on-disk hash table representation.
@@ -4238,7 +4234,8 @@ void ASTWriter::GenerateSpecializationInfoLookupTable(
}
auto *Lookups =
- Chain ? Chain->getLoadedSpecializationsLookupTables(D) : nullptr;
+ Chain ? Chain->getLoadedSpecializationsLookupTables(D, IsPartial)
+ : nullptr;
for (auto &[HashValue, Specs] : SpecializationMaps) {
SmallVector<serialization::reader::LazySpecializationInfo, 16> ExisitingSpecs;
@@ -4258,14 +4255,19 @@ void ASTWriter::GenerateSpecializationInfoLookupTable(
}
uint64_t ASTWriter::WriteSpecializationInfoLookupTable(
- const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations) {
+ const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
+ bool IsPartial) {
llvm::SmallString<4096> LookupTable;
- GenerateSpecializationInfoLookupTable(D, Specializations, LookupTable);
+ GenerateSpecializationInfoLookupTable(D, Specializations, LookupTable,
+ IsPartial);
uint64_t Offset = Stream.GetCurrentBitNo();
- RecordData::value_type Record[] = {DECL_SPECIALIZATIONS};
- Stream.EmitRecordWithBlob(DeclSpecializationsAbbrev, Record, LookupTable);
+ RecordData::value_type Record[] = {IsPartial ? DECL_PARTIAL_SPECIALIZATIONS
+ : DECL_SPECIALIZATIONS};
+ Stream.EmitRecordWithBlob(IsPartial ? DeclPartialSpecializationsAbbrev
+ : DeclSpecializationsAbbrev,
+ Record, LookupTable);
return Offset;
}
@@ -5888,8 +5890,15 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
FunctionToLambdaMapAbbrev);
}
- if (!SpecializationsUpdates.empty())
- WriteSpecializationsUpdates();
+ 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
@@ -5934,23 +5943,27 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
WriteDeclContextVisibleUpdate(Context, DC);
}
-void ASTWriter::WriteSpecializationsUpdates() {
+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(CXX_ADDED_TEMPLATE_SPECIALIZATION));
+ 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));
- for (auto &SpecializationUpdate : SpecializationsUpdates) {
+ auto &SpecUpdates =
+ IsPartial ? PartialSpecializationsUpdates : SpecializationsUpdates;
+ for (auto &SpecializationUpdate : SpecUpdates) {
const NamedDecl *D = SpecializationUpdate.first;
llvm::SmallString<4096> LookupTable;
GenerateSpecializationInfoLookupTable(D, SpecializationUpdate.second,
- LookupTable);
+ LookupTable, IsPartial);
// Write the lookup table
- RecordData::value_type Record[] = {CXX_ADDED_TEMPLATE_SPECIALIZATION,
- getDeclID(D).getRawValue()};
+ RecordData::value_type Record[] = {RecordType, getDeclID(D).getRawValue()};
Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable);
}
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 78c4f3bd62c33f..b3119607a14043 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -208,15 +208,21 @@ namespace clang {
/// ODRHash of the template arguments of D which should provide enough
/// information to load D only if the template instantiator needs it.
void AddFirstSpecializationDeclFromEachModule(
- const Decl *D, llvm::SmallVectorImpl<const Decl *> &SpecsInMap) {
+ 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)
- SpecsInMap.push_back(F.second);
+ 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.
@@ -243,29 +249,38 @@ namespace clang {
// If we have any lazy specializations, and the external AST source is
// our chained AST reader, we can just write out the DeclIDs. Otherwise,
// we need to resolve them to actual declarations.
- if (Writer.Chain != Writer.Context->getExternalSource() && Writer.Chain &&
- Writer.Chain->getLoadedSpecializationsLookupTables(D)) {
+ if (Writer.Chain != Record.getASTContext().getExternalSource() &&
+ Writer.Chain && Writer.Chain->haveUnloadedSpecializations(D)) {
D->LoadLazySpecializations();
- assert(!Writer.Chain->getLoadedSpecializationsLookupTables(D));
+ assert(!Writer.Chain->haveUnloadedSpecializations(D));
}
- // AddFirstDeclFromEachModule might trigger deserialization, invalidating
- // *Specializations iterators.
- llvm::SmallVector<const Decl*, 16> Specs;
+ // AddFirstSpecializationDeclFromEachModule might trigger deserialization,
+ // invalidating *Specializations iterators.
+ llvm::SmallVector<const Decl *, 16> AllSpecs;
for (auto &Entry : Common->Specializations)
- Specs.push_back(getSpecializationDecl(Entry));
+ AllSpecs.push_back(getSpecializationDecl(Entry));
for (auto &Entry : getPartialSpecializations(Common))
- Specs.push_back(getSpecializationDecl(Entry));
-
- llvm::SmallVector<const Decl *, 16> SpecsInOnDiskMap = Specs;
+ AllSpecs.push_back(getSpecializationDecl(Entry));
- for (auto *D : Specs) {
+ llvm::SmallVector<const Decl *, 16> Specs;
+ llvm::SmallVector<const Decl *, 16> PartialSpecs;
+ for (auto *D : AllSpecs) {
assert(D->isCanonicalDecl() && "non-canonical decl in set");
- AddFirstSpecializationDeclFromEachModule(D, SpecsInOnDiskMap);
+ AddFirstSpecializationDeclFromEachModule(D, Specs, PartialSpecs);
}
- Record.AddOffset(
- Writer.WriteSpecializationInfoLookupTable(D, SpecsInOnDiskMap));
+ Record.AddOffset(Writer.WriteSpecializationInfoLookupTable(
+ D, Specs, /*IsPartial=*/false));
+
+ // Function Template Decl doesn't have partial decls.
+ if (isa<FunctionTemplateDecl>(D)) {
+ assert(PartialSpecs.empty());
+ return;
+ }
+
+ Record.AddOffset(Writer.WriteSpecializationInfoLookupTable(
+ D, PartialSpecs, /*IsPartial=*/true));
}
/// Ensure that this template specialization is associated with the specified
@@ -286,8 +301,13 @@ namespace clang {
if (Writer.getFirstLocalDecl(Specialization) != Specialization)
return;
- Writer.SpecializationsUpdates[cast<NamedDecl>(Template)].push_back(
- cast<NamedDecl>(Specialization));
+ 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));
}
};
}
@@ -2797,6 +2817,11 @@ void ASTWriter::WriteDeclAbbrevs() {
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
More information about the llvm-branch-commits
mailing list