Skip to content

Commit 0d8de51

Browse files
vgvassilevChuanqiXu9
authored andcommitted
D41416: [modules] [pch] Do not deserialize all lazy template specializations when looking for one.
1 parent 6bb72de commit 0d8de51

File tree

9 files changed

+257
-72
lines changed

9 files changed

+257
-72
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,
@@ -729,6 +732,26 @@ class RedeclarableTemplateDecl : public TemplateDecl,
729732
}
730733

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

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

774802
template <class EntryType, typename ...ProfileArguments>
775803
typename SpecEntryTraits<EntryType>::DeclType*
@@ -792,7 +820,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
792820
///
793821
/// The first value in the array is the number of specializations/partial
794822
/// specializations that follow.
795-
GlobalDeclID *LazySpecializations = nullptr;
823+
LazySpecializationInfo *LazySpecializations = nullptr;
796824

797825
/// The set of "injected" template arguments used within this
798826
/// template.
@@ -2299,7 +2327,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
22992327
friend class TemplateDeclInstantiator;
23002328

23012329
/// Load any lazily-loaded specializations from the external source.
2302-
void LoadLazySpecializations() const;
2330+
void LoadLazySpecializations(bool OnlyPartial = false) const;
23032331

23042332
/// Get the underlying class declarations of the template.
23052333
CXXRecordDecl *getTemplatedDecl() const {
@@ -3060,7 +3088,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
30603088
friend class ASTDeclWriter;
30613089

30623090
/// Load any lazily-loaded specializations from the external source.
3063-
void LoadLazySpecializations() const;
3091+
void LoadLazySpecializations(bool OnlyPartial = false) const;
30643092

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

clang/lib/AST/DeclTemplate.cpp

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
#include "clang/AST/DeclCXX.h"
1717
#include "clang/AST/DeclarationName.h"
1818
#include "clang/AST/Expr.h"
19+
#include "clang/AST/ExprCXX.h"
1920
#include "clang/AST/ExternalASTSource.h"
21+
#include "clang/AST/ODRHash.h"
2022
#include "clang/AST/TemplateBase.h"
2123
#include "clang/AST/TemplateName.h"
2224
#include "clang/AST/Type.h"
@@ -340,17 +342,44 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
340342
return getCommonPtrInternal();
341343
}
342344

343-
void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
345+
void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
346+
bool OnlyPartial /*=false*/) const {
344347
// Grab the most recent declaration to ensure we've loaded any lazy
345348
// redeclarations of this template.
346349
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
347-
if (CommonBasePtr->LazySpecializations) {
348-
ASTContext &Context = getASTContext();
349-
GlobalDeclID *Specs = CommonBasePtr->LazySpecializations;
350-
CommonBasePtr->LazySpecializations = nullptr;
351-
unsigned SpecSize = (*Specs++).getRawValue();
352-
for (unsigned I = 0; I != SpecSize; ++I)
353-
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
350+
if (auto *Specs = CommonBasePtr->LazySpecializations) {
351+
if (!OnlyPartial)
352+
CommonBasePtr->LazySpecializations = nullptr;
353+
unsigned N = Specs[0].DeclID.getRawValue();
354+
for (unsigned I = 0; I != N; ++I) {
355+
// Skip over already loaded specializations.
356+
if (!Specs[I + 1].ODRHash)
357+
continue;
358+
if (!OnlyPartial || Specs[I + 1].IsPartial)
359+
(void)loadLazySpecializationImpl(Specs[I + 1]);
360+
}
361+
}
362+
}
363+
364+
Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl(
365+
LazySpecializationInfo &LazySpecInfo) const {
366+
GlobalDeclID ID = LazySpecInfo.DeclID;
367+
assert(ID.isValid() && "Loading already loaded specialization!");
368+
// Note that we loaded the specialization.
369+
LazySpecInfo.DeclID = GlobalDeclID();
370+
LazySpecInfo.ODRHash = LazySpecInfo.IsPartial = 0;
371+
return getASTContext().getExternalSource()->GetExternalDecl(ID);
372+
}
373+
374+
void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
375+
ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const {
376+
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
377+
if (auto *Specs = CommonBasePtr->LazySpecializations) {
378+
unsigned Hash = TemplateArgumentList::ComputeODRHash(Args);
379+
unsigned N = Specs[0].DeclID.getRawValue();
380+
for (unsigned I = 0; I != N; ++I)
381+
if (Specs[I + 1].ODRHash && Specs[I + 1].ODRHash == Hash)
382+
(void)loadLazySpecializationImpl(Specs[I + 1]);
354383
}
355384
}
356385

@@ -361,6 +390,8 @@ RedeclarableTemplateDecl::findSpecializationImpl(
361390
ProfileArguments&&... ProfileArgs) {
362391
using SETraits = SpecEntryTraits<EntryType>;
363392

393+
loadLazySpecializationsImpl(std::forward<ProfileArguments>(ProfileArgs)...);
394+
364395
llvm::FoldingSetNodeID ID;
365396
EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
366397
getASTContext());
@@ -376,10 +407,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
376407

377408
if (InsertPos) {
378409
#ifndef NDEBUG
410+
auto Args = SETraits::getTemplateArgs(Entry);
411+
// Due to hash collisions, it can happen that we load another template
412+
// specialization with the same hash. This is fine, as long as the next
413+
// call to findSpecializationImpl does not find a matching Decl for the
414+
// template arguments.
415+
loadLazySpecializationsImpl(Args);
379416
void *CorrectInsertPos;
380-
assert(!findSpecializationImpl(Specializations,
381-
CorrectInsertPos,
382-
SETraits::getTemplateArgs(Entry)) &&
417+
assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) &&
383418
InsertPos == CorrectInsertPos &&
384419
"given incorrect InsertPos for specialization");
385420
#endif
@@ -453,12 +488,14 @@ FunctionTemplateDecl::getSpecializations() const {
453488
FunctionDecl *
454489
FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
455490
void *&InsertPos) {
456-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
491+
auto *Common = getCommonPtr();
492+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
457493
}
458494

459495
void FunctionTemplateDecl::addSpecialization(
460496
FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
461-
addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info,
497+
auto *Common = getCommonPtr();
498+
addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info,
462499
InsertPos);
463500
}
464501

@@ -516,8 +553,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
516553
DeclarationName(), nullptr, nullptr);
517554
}
518555

519-
void ClassTemplateDecl::LoadLazySpecializations() const {
520-
loadLazySpecializationsImpl();
556+
void ClassTemplateDecl::LoadLazySpecializations(
557+
bool OnlyPartial /*=false*/) const {
558+
loadLazySpecializationsImpl(OnlyPartial);
521559
}
522560

523561
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
@@ -528,7 +566,7 @@ ClassTemplateDecl::getSpecializations() const {
528566

529567
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
530568
ClassTemplateDecl::getPartialSpecializations() const {
531-
LoadLazySpecializations();
569+
LoadLazySpecializations(/*PartialOnly = */ true);
532570
return getCommonPtr()->PartialSpecializations;
533571
}
534572

@@ -542,12 +580,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
542580
ClassTemplateSpecializationDecl *
543581
ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
544582
void *&InsertPos) {
545-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
583+
auto *Common = getCommonPtr();
584+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
546585
}
547586

548587
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
549588
void *InsertPos) {
550-
addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos);
589+
auto *Common = getCommonPtr();
590+
addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D,
591+
InsertPos);
551592
}
552593

553594
ClassTemplatePartialSpecializationDecl *
@@ -904,6 +945,14 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
904945
return new (Mem) TemplateArgumentList(Args);
905946
}
906947

948+
unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) {
949+
ODRHash Hasher;
950+
for (TemplateArgument TA : Args)
951+
Hasher.AddTemplateArgument(TA);
952+
953+
return Hasher.CalculateHash();
954+
}
955+
907956
FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
908957
ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
909958
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
@@ -1283,8 +1332,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
12831332
DeclarationName(), nullptr, nullptr);
12841333
}
12851334

1286-
void VarTemplateDecl::LoadLazySpecializations() const {
1287-
loadLazySpecializationsImpl();
1335+
void VarTemplateDecl::LoadLazySpecializations(
1336+
bool OnlyPartial /*=false*/) const {
1337+
loadLazySpecializationsImpl(OnlyPartial);
12881338
}
12891339

12901340
llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
@@ -1295,7 +1345,7 @@ VarTemplateDecl::getSpecializations() const {
12951345

12961346
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
12971347
VarTemplateDecl::getPartialSpecializations() const {
1298-
LoadLazySpecializations();
1348+
LoadLazySpecializations(/*PartialOnly = */ true);
12991349
return getCommonPtr()->PartialSpecializations;
13001350
}
13011351

@@ -1309,12 +1359,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
13091359
VarTemplateSpecializationDecl *
13101360
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
13111361
void *&InsertPos) {
1312-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
1362+
auto *Common = getCommonPtr();
1363+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
13131364
}
13141365

13151366
void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
13161367
void *InsertPos) {
1317-
addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos);
1368+
auto *Common = getCommonPtr();
1369+
addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos);
13181370
}
13191371

13201372
VarTemplatePartialSpecializationDecl *

clang/lib/AST/ODRHash.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,21 @@ void ODRHash::AddDecl(const Decl *D) {
828828
for (const TemplateArgument &TA : List.asArray())
829829
AddTemplateArgument(TA);
830830
}
831+
832+
// If this was a specialization we should take into account its template
833+
// arguments. This helps to reduce collisions coming when visiting template
834+
// specialization types (eg. when processing type template arguments).
835+
ArrayRef<TemplateArgument> Args;
836+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
837+
Args = CTSD->getTemplateArgs().asArray();
838+
else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
839+
Args = VTSD->getTemplateArgs().asArray();
840+
else if (auto *FD = dyn_cast<FunctionDecl>(D))
841+
if (FD->getTemplateSpecializationArgs())
842+
Args = FD->getTemplateSpecializationArgs()->asArray();
843+
844+
for (auto &TA : Args)
845+
AddTemplateArgument(TA);
831846
}
832847

833848
namespace {

clang/lib/Serialization/ASTReader.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7660,14 +7660,23 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
76607660
}
76617661
}
76627662

7663-
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
7664-
CTSD->getSpecializedTemplate()->LoadLazySpecializations();
7665-
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
7666-
VTSD->getSpecializedTemplate()->LoadLazySpecializations();
7667-
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7668-
if (auto *Template = FD->getPrimaryTemplate())
7669-
Template->LoadLazySpecializations();
7670-
}
7663+
RedeclarableTemplateDecl *Template = nullptr;
7664+
ArrayRef<TemplateArgument> Args;
7665+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
7666+
Template = CTSD->getSpecializedTemplate();
7667+
Args = CTSD->getTemplateArgs().asArray();
7668+
} else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
7669+
Template = VTSD->getSpecializedTemplate();
7670+
Args = VTSD->getTemplateArgs().asArray();
7671+
} else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7672+
if (auto *Tmplt = FD->getPrimaryTemplate()) {
7673+
Template = Tmplt;
7674+
Args = FD->getTemplateSpecializationArgs()->asArray();
7675+
}
7676+
}
7677+
7678+
if (Template)
7679+
Template->loadLazySpecializationsImpl(Args);
76717680
}
76727681

76737682
CXXCtorInitializer **

0 commit comments

Comments
 (0)