Skip to content

Commit 2a9dfda

Browse files
vgvassilevChuanqiXu9
authored andcommitted
D41416: [modules] [pch] Do not deserialize all lazy template specializations when looking for one.
1 parent 8389b3b commit 2a9dfda

File tree

7 files changed

+242
-61
lines changed

7 files changed

+242
-61
lines changed

clang/include/clang/AST/DeclTemplate.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ class TemplateArgumentList final
256256
TemplateArgumentList(const TemplateArgumentList &) = delete;
257257
TemplateArgumentList &operator=(const TemplateArgumentList &) = delete;
258258

259+
/// Create hash for the given arguments.
260+
static unsigned ComputeODRHash(ArrayRef<TemplateArgument> Args);
261+
259262
/// Create a new template argument list that copies the given set of
260263
/// template arguments.
261264
static TemplateArgumentList *CreateCopy(ASTContext &Context,
@@ -730,6 +733,26 @@ class RedeclarableTemplateDecl : public TemplateDecl,
730733
}
731734

732735
void anchor() override;
736+
struct LazySpecializationInfo {
737+
uint32_t DeclID = ~0U;
738+
unsigned ODRHash = ~0U;
739+
bool IsPartial = false;
740+
LazySpecializationInfo(uint32_t ID, unsigned Hash = ~0U,
741+
bool Partial = false)
742+
: DeclID(ID), ODRHash(Hash), IsPartial(Partial) { }
743+
LazySpecializationInfo() { }
744+
bool operator<(const LazySpecializationInfo &Other) const {
745+
return DeclID < Other.DeclID;
746+
}
747+
bool operator==(const LazySpecializationInfo &Other) const {
748+
assert((DeclID != Other.DeclID || ODRHash == Other.ODRHash) &&
749+
"Hashes differ!");
750+
assert((DeclID != Other.DeclID || IsPartial == Other.IsPartial) &&
751+
"Both must be the same kinds!");
752+
return DeclID == Other.DeclID;
753+
}
754+
};
755+
733756
protected:
734757
template <typename EntryType> struct SpecEntryTraits {
735758
using DeclType = EntryType;
@@ -770,7 +793,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
770793
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
771794
}
772795

773-
void loadLazySpecializationsImpl() const;
796+
void loadLazySpecializationsImpl(bool OnlyPartial = false) const;
797+
798+
void loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
799+
TemplateParameterList *TPL = nullptr) const;
800+
801+
Decl *loadLazySpecializationImpl(LazySpecializationInfo &LazySpecInfo) const;
774802

775803
template <class EntryType, typename ...ProfileArguments>
776804
typename SpecEntryTraits<EntryType>::DeclType*
@@ -797,7 +825,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
797825
///
798826
/// The first value in the array is the number of specializations/partial
799827
/// specializations that follow.
800-
uint32_t *LazySpecializations = nullptr;
828+
LazySpecializationInfo *LazySpecializations = nullptr;
801829

802830
/// The set of "injected" template arguments used within this
803831
/// template.
@@ -2268,7 +2296,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
22682296
friend class TemplateDeclInstantiator;
22692297

22702298
/// Load any lazily-loaded specializations from the external source.
2271-
void LoadLazySpecializations() const;
2299+
void LoadLazySpecializations(bool OnlyPartial = false) const;
22722300

22732301
/// Get the underlying class declarations of the template.
22742302
CXXRecordDecl *getTemplatedDecl() const {
@@ -3039,7 +3067,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
30393067
friend class ASTDeclWriter;
30403068

30413069
/// Load any lazily-loaded specializations from the external source.
3042-
void LoadLazySpecializations() const;
3070+
void LoadLazySpecializations(bool OnlyPartial = false) const;
30433071

30443072
/// Get the underlying variable declarations of the template.
30453073
VarDecl *getTemplatedDecl() const {

clang/lib/AST/DeclTemplate.cpp

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "clang/AST/TemplateBase.h"
2121
#include "clang/AST/TemplateName.h"
2222
#include "clang/AST/Type.h"
23+
#include "clang/AST/ODRHash.h"
24+
#include "clang/AST/ExprCXX.h"
2325
#include "clang/AST/TypeLoc.h"
2426
#include "clang/Basic/Builtins.h"
2527
#include "clang/Basic/LLVM.h"
@@ -331,16 +333,43 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
331333
return Common;
332334
}
333335

334-
void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
336+
void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
337+
bool OnlyPartial/*=false*/) const {
335338
// Grab the most recent declaration to ensure we've loaded any lazy
336339
// redeclarations of this template.
337340
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
338-
if (CommonBasePtr->LazySpecializations) {
339-
ASTContext &Context = getASTContext();
340-
uint32_t *Specs = CommonBasePtr->LazySpecializations;
341-
CommonBasePtr->LazySpecializations = nullptr;
342-
for (uint32_t I = 0, N = *Specs++; I != N; ++I)
343-
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
341+
if (auto *Specs = CommonBasePtr->LazySpecializations) {
342+
if (!OnlyPartial)
343+
CommonBasePtr->LazySpecializations = nullptr;
344+
for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I) {
345+
// Skip over already loaded specializations.
346+
if (!Specs[I+1].ODRHash)
347+
continue;
348+
if (!OnlyPartial || Specs[I+1].IsPartial)
349+
(void)loadLazySpecializationImpl(Specs[I+1]);
350+
}
351+
}
352+
}
353+
354+
Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl(
355+
LazySpecializationInfo &LazySpecInfo) const {
356+
uint32_t ID = LazySpecInfo.DeclID;
357+
assert(ID && "Loading already loaded specialization!");
358+
// Note that we loaded the specialization.
359+
LazySpecInfo.DeclID = LazySpecInfo.ODRHash = LazySpecInfo.IsPartial = 0;
360+
return getASTContext().getExternalSource()->GetExternalDecl(ID);
361+
}
362+
363+
void
364+
RedeclarableTemplateDecl::loadLazySpecializationsImpl(ArrayRef<TemplateArgument>
365+
Args,
366+
TemplateParameterList *TPL) const {
367+
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
368+
if (auto *Specs = CommonBasePtr->LazySpecializations) {
369+
unsigned Hash = TemplateArgumentList::ComputeODRHash(Args);
370+
for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I)
371+
if (Specs[I+1].ODRHash && Specs[I+1].ODRHash == Hash)
372+
(void)loadLazySpecializationImpl(Specs[I+1]);
344373
}
345374
}
346375

@@ -351,6 +380,8 @@ RedeclarableTemplateDecl::findSpecializationImpl(
351380
ProfileArguments&&... ProfileArgs) {
352381
using SETraits = SpecEntryTraits<EntryType>;
353382

383+
loadLazySpecializationsImpl(std::forward<ProfileArguments>(ProfileArgs)...);
384+
354385
llvm::FoldingSetNodeID ID;
355386
EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
356387
getASTContext());
@@ -366,10 +397,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
366397

367398
if (InsertPos) {
368399
#ifndef NDEBUG
400+
auto Args = SETraits::getTemplateArgs(Entry);
401+
// Due to hash collisions, it can happen that we load another template
402+
// specialization with the same hash. This is fine, as long as the next
403+
// call to findSpecializationImpl does not find a matching Decl for the
404+
// template arguments.
405+
loadLazySpecializationsImpl(Args);
369406
void *CorrectInsertPos;
370-
assert(!findSpecializationImpl(Specializations,
371-
CorrectInsertPos,
372-
SETraits::getTemplateArgs(Entry)) &&
407+
assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) &&
373408
InsertPos == CorrectInsertPos &&
374409
"given incorrect InsertPos for specialization");
375410
#endif
@@ -443,12 +478,14 @@ FunctionTemplateDecl::getSpecializations() const {
443478
FunctionDecl *
444479
FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
445480
void *&InsertPos) {
446-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
481+
auto *Common = getCommonPtr();
482+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
447483
}
448484

449485
void FunctionTemplateDecl::addSpecialization(
450486
FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
451-
addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info,
487+
auto *Common = getCommonPtr();
488+
addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info,
452489
InsertPos);
453490
}
454491

@@ -508,8 +545,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
508545
DeclarationName(), nullptr, nullptr);
509546
}
510547

511-
void ClassTemplateDecl::LoadLazySpecializations() const {
512-
loadLazySpecializationsImpl();
548+
void ClassTemplateDecl::LoadLazySpecializations(
549+
bool OnlyPartial/*=false*/) const {
550+
loadLazySpecializationsImpl(OnlyPartial);
513551
}
514552

515553
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
@@ -520,7 +558,7 @@ ClassTemplateDecl::getSpecializations() const {
520558

521559
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
522560
ClassTemplateDecl::getPartialSpecializations() const {
523-
LoadLazySpecializations();
561+
LoadLazySpecializations(/*PartialOnly = */ true);
524562
return getCommonPtr()->PartialSpecializations;
525563
}
526564

@@ -534,12 +572,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
534572
ClassTemplateSpecializationDecl *
535573
ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
536574
void *&InsertPos) {
537-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
575+
auto *Common = getCommonPtr();
576+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
538577
}
539578

540579
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
541580
void *InsertPos) {
542-
addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos);
581+
auto *Common = getCommonPtr();
582+
addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D,
583+
InsertPos);
543584
}
544585

545586
ClassTemplatePartialSpecializationDecl *
@@ -883,6 +924,14 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
883924
return new (Mem) TemplateArgumentList(Args);
884925
}
885926

927+
unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) {
928+
ODRHash Hasher;
929+
for (TemplateArgument TA : Args)
930+
Hasher.AddTemplateArgument(TA);
931+
932+
return Hasher.CalculateHash();
933+
}
934+
886935
FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
887936
ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
888937
TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs,
@@ -1225,8 +1274,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
12251274
DeclarationName(), nullptr, nullptr);
12261275
}
12271276

1228-
void VarTemplateDecl::LoadLazySpecializations() const {
1229-
loadLazySpecializationsImpl();
1277+
void VarTemplateDecl::LoadLazySpecializations(
1278+
bool OnlyPartial/*=false*/) const {
1279+
loadLazySpecializationsImpl(OnlyPartial);
12301280
}
12311281

12321282
llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
@@ -1237,7 +1287,7 @@ VarTemplateDecl::getSpecializations() const {
12371287

12381288
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
12391289
VarTemplateDecl::getPartialSpecializations() const {
1240-
LoadLazySpecializations();
1290+
LoadLazySpecializations(/*PartialOnly = */ true);
12411291
return getCommonPtr()->PartialSpecializations;
12421292
}
12431293

@@ -1251,12 +1301,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
12511301
VarTemplateSpecializationDecl *
12521302
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
12531303
void *&InsertPos) {
1254-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
1304+
auto *Common = getCommonPtr();
1305+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
12551306
}
12561307

12571308
void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
12581309
void *InsertPos) {
1259-
addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos);
1310+
auto *Common = getCommonPtr();
1311+
addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos);
12601312
}
12611313

12621314
VarTemplatePartialSpecializationDecl *

clang/lib/AST/ODRHash.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,21 @@ void ODRHash::AddDecl(const Decl *D) {
812812
for (const TemplateArgument &TA : List.asArray())
813813
AddTemplateArgument(TA);
814814
}
815+
816+
// If this was a specialization we should take into account its template
817+
// arguments. This helps to reduce collisions coming when visiting template
818+
// specialization types (eg. when processing type template arguments).
819+
ArrayRef<TemplateArgument> Args;
820+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
821+
Args = CTSD->getTemplateArgs().asArray();
822+
else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
823+
Args = VTSD->getTemplateArgs().asArray();
824+
else if (auto *FD = dyn_cast<FunctionDecl>(D))
825+
if (FD->getTemplateSpecializationArgs())
826+
Args = FD->getTemplateSpecializationArgs()->asArray();
827+
828+
for (auto &TA : Args)
829+
AddTemplateArgument(TA);
815830
}
816831

817832
namespace {

clang/lib/Serialization/ASTReader.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7559,14 +7559,23 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
75597559
}
75607560
}
75617561

7562-
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
7563-
CTSD->getSpecializedTemplate()->LoadLazySpecializations();
7564-
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
7565-
VTSD->getSpecializedTemplate()->LoadLazySpecializations();
7566-
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7567-
if (auto *Template = FD->getPrimaryTemplate())
7568-
Template->LoadLazySpecializations();
7569-
}
7562+
RedeclarableTemplateDecl *Template = nullptr;
7563+
ArrayRef<TemplateArgument> Args;
7564+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
7565+
Template = CTSD->getSpecializedTemplate();
7566+
Args = CTSD->getTemplateArgs().asArray();
7567+
} else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
7568+
Template = VTSD->getSpecializedTemplate();
7569+
Args = VTSD->getTemplateArgs().asArray();
7570+
} else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7571+
if (auto *Tmplt = FD->getPrimaryTemplate()) {
7572+
Template = Tmplt;
7573+
Args = FD->getTemplateSpecializationArgs()->asArray();
7574+
}
7575+
}
7576+
7577+
if (Template)
7578+
Template->loadLazySpecializationsImpl(Args);
75707579
}
75717580

75727581
CXXCtorInitializer **

0 commit comments

Comments
 (0)