Skip to content

Commit a526580

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

File tree

9 files changed

+258
-73
lines changed

9 files changed

+258
-73
lines changed

clang/include/clang/AST/DeclTemplate.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ class TemplateArgumentList final
262262
TemplateArgumentList(const TemplateArgumentList &) = delete;
263263
TemplateArgumentList &operator=(const TemplateArgumentList &) = delete;
264264

265+
/// Create hash for the given arguments.
266+
static unsigned ComputeODRHash(ArrayRef<TemplateArgument> Args);
267+
265268
/// Create a new template argument list that copies the given set of
266269
/// template arguments.
267270
static TemplateArgumentList *CreateCopy(ASTContext &Context,
@@ -735,6 +738,26 @@ class RedeclarableTemplateDecl : public TemplateDecl,
735738
}
736739

737740
void anchor() override;
741+
struct LazySpecializationInfo {
742+
GlobalDeclID DeclID = GlobalDeclID();
743+
unsigned ODRHash = ~0U;
744+
bool IsPartial = false;
745+
LazySpecializationInfo(GlobalDeclID ID, unsigned Hash = ~0U,
746+
bool Partial = false)
747+
: DeclID(ID), ODRHash(Hash), IsPartial(Partial) {}
748+
LazySpecializationInfo() {}
749+
bool operator<(const LazySpecializationInfo &Other) const {
750+
return DeclID < Other.DeclID;
751+
}
752+
bool operator==(const LazySpecializationInfo &Other) const {
753+
assert((DeclID != Other.DeclID || ODRHash == Other.ODRHash) &&
754+
"Hashes differ!");
755+
assert((DeclID != Other.DeclID || IsPartial == Other.IsPartial) &&
756+
"Both must be the same kinds!");
757+
return DeclID == Other.DeclID;
758+
}
759+
};
760+
738761
protected:
739762
template <typename EntryType> struct SpecEntryTraits {
740763
using DeclType = EntryType;
@@ -775,7 +798,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
775798
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
776799
}
777800

778-
void loadLazySpecializationsImpl() const;
801+
void loadLazySpecializationsImpl(bool OnlyPartial = false) const;
802+
803+
void loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
804+
TemplateParameterList *TPL = nullptr) const;
805+
806+
Decl *loadLazySpecializationImpl(LazySpecializationInfo &LazySpecInfo) const;
779807

780808
template <class EntryType, typename ...ProfileArguments>
781809
typename SpecEntryTraits<EntryType>::DeclType*
@@ -802,7 +830,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
802830
///
803831
/// The first value in the array is the number of specializations/partial
804832
/// specializations that follow.
805-
GlobalDeclID *LazySpecializations = nullptr;
833+
LazySpecializationInfo *LazySpecializations = nullptr;
806834
};
807835

808836
/// Pointer to the common data shared by all declarations of this
@@ -2283,7 +2311,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
22832311
friend class TemplateDeclInstantiator;
22842312

22852313
/// Load any lazily-loaded specializations from the external source.
2286-
void LoadLazySpecializations() const;
2314+
void LoadLazySpecializations(bool OnlyPartial = false) const;
22872315

22882316
/// Get the underlying class declarations of the template.
22892317
CXXRecordDecl *getTemplatedDecl() const {
@@ -3033,7 +3061,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
30333061
friend class ASTDeclWriter;
30343062

30353063
/// Load any lazily-loaded specializations from the external source.
3036-
void LoadLazySpecializations() const;
3064+
void LoadLazySpecializations(bool OnlyPartial = false) const;
30373065

30383066
/// Get the underlying variable declarations of the template.
30393067
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"
@@ -351,17 +353,44 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
351353
return Common;
352354
}
353355

354-
void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
356+
void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
357+
bool OnlyPartial /*=false*/) const {
355358
// Grab the most recent declaration to ensure we've loaded any lazy
356359
// redeclarations of this template.
357360
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
358-
if (CommonBasePtr->LazySpecializations) {
359-
ASTContext &Context = getASTContext();
360-
GlobalDeclID *Specs = CommonBasePtr->LazySpecializations;
361-
CommonBasePtr->LazySpecializations = nullptr;
362-
unsigned SpecSize = (*Specs++).getRawValue();
363-
for (unsigned I = 0; I != SpecSize; ++I)
364-
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
361+
if (auto *Specs = CommonBasePtr->LazySpecializations) {
362+
if (!OnlyPartial)
363+
CommonBasePtr->LazySpecializations = nullptr;
364+
unsigned N = Specs[0].DeclID.getRawValue();
365+
for (unsigned I = 0; I != N; ++I) {
366+
// Skip over already loaded specializations.
367+
if (!Specs[I + 1].ODRHash)
368+
continue;
369+
if (!OnlyPartial || Specs[I + 1].IsPartial)
370+
(void)loadLazySpecializationImpl(Specs[I + 1]);
371+
}
372+
}
373+
}
374+
375+
Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl(
376+
LazySpecializationInfo &LazySpecInfo) const {
377+
GlobalDeclID ID = LazySpecInfo.DeclID;
378+
assert(ID.isValid() && "Loading already loaded specialization!");
379+
// Note that we loaded the specialization.
380+
LazySpecInfo.DeclID = GlobalDeclID();
381+
LazySpecInfo.ODRHash = LazySpecInfo.IsPartial = 0;
382+
return getASTContext().getExternalSource()->GetExternalDecl(ID);
383+
}
384+
385+
void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
386+
ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const {
387+
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
388+
if (auto *Specs = CommonBasePtr->LazySpecializations) {
389+
unsigned Hash = TemplateArgumentList::ComputeODRHash(Args);
390+
unsigned N = Specs[0].DeclID.getRawValue();
391+
for (unsigned I = 0; I != N; ++I)
392+
if (Specs[I + 1].ODRHash && Specs[I + 1].ODRHash == Hash)
393+
(void)loadLazySpecializationImpl(Specs[I + 1]);
365394
}
366395
}
367396

@@ -372,6 +401,8 @@ RedeclarableTemplateDecl::findSpecializationImpl(
372401
ProfileArguments&&... ProfileArgs) {
373402
using SETraits = SpecEntryTraits<EntryType>;
374403

404+
loadLazySpecializationsImpl(std::forward<ProfileArguments>(ProfileArgs)...);
405+
375406
llvm::FoldingSetNodeID ID;
376407
EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
377408
getASTContext());
@@ -387,10 +418,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
387418

388419
if (InsertPos) {
389420
#ifndef NDEBUG
421+
auto Args = SETraits::getTemplateArgs(Entry);
422+
// Due to hash collisions, it can happen that we load another template
423+
// specialization with the same hash. This is fine, as long as the next
424+
// call to findSpecializationImpl does not find a matching Decl for the
425+
// template arguments.
426+
loadLazySpecializationsImpl(Args);
390427
void *CorrectInsertPos;
391-
assert(!findSpecializationImpl(Specializations,
392-
CorrectInsertPos,
393-
SETraits::getTemplateArgs(Entry)) &&
428+
assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) &&
394429
InsertPos == CorrectInsertPos &&
395430
"given incorrect InsertPos for specialization");
396431
#endif
@@ -448,12 +483,14 @@ FunctionTemplateDecl::getSpecializations() const {
448483
FunctionDecl *
449484
FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
450485
void *&InsertPos) {
451-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
486+
auto *Common = getCommonPtr();
487+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
452488
}
453489

454490
void FunctionTemplateDecl::addSpecialization(
455491
FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
456-
addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info,
492+
auto *Common = getCommonPtr();
493+
addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info,
457494
InsertPos);
458495
}
459496

@@ -513,8 +550,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
513550
DeclarationName(), nullptr, nullptr);
514551
}
515552

516-
void ClassTemplateDecl::LoadLazySpecializations() const {
517-
loadLazySpecializationsImpl();
553+
void ClassTemplateDecl::LoadLazySpecializations(
554+
bool OnlyPartial /*=false*/) const {
555+
loadLazySpecializationsImpl(OnlyPartial);
518556
}
519557

520558
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
@@ -525,7 +563,7 @@ ClassTemplateDecl::getSpecializations() const {
525563

526564
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
527565
ClassTemplateDecl::getPartialSpecializations() const {
528-
LoadLazySpecializations();
566+
LoadLazySpecializations(/*PartialOnly = */ true);
529567
return getCommonPtr()->PartialSpecializations;
530568
}
531569

@@ -539,12 +577,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
539577
ClassTemplateSpecializationDecl *
540578
ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
541579
void *&InsertPos) {
542-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
580+
auto *Common = getCommonPtr();
581+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
543582
}
544583

545584
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
546585
void *InsertPos) {
547-
addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos);
586+
auto *Common = getCommonPtr();
587+
addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D,
588+
InsertPos);
548589
}
549590

550591
ClassTemplatePartialSpecializationDecl *
@@ -897,6 +938,14 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
897938
return new (Mem) TemplateArgumentList(Args);
898939
}
899940

941+
unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) {
942+
ODRHash Hasher;
943+
for (TemplateArgument TA : Args)
944+
Hasher.AddTemplateArgument(TA);
945+
946+
return Hasher.CalculateHash();
947+
}
948+
900949
FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
901950
ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
902951
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
@@ -1262,8 +1311,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
12621311
DeclarationName(), nullptr, nullptr);
12631312
}
12641313

1265-
void VarTemplateDecl::LoadLazySpecializations() const {
1266-
loadLazySpecializationsImpl();
1314+
void VarTemplateDecl::LoadLazySpecializations(
1315+
bool OnlyPartial /*=false*/) const {
1316+
loadLazySpecializationsImpl(OnlyPartial);
12671317
}
12681318

12691319
llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
@@ -1274,7 +1324,7 @@ VarTemplateDecl::getSpecializations() const {
12741324

12751325
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
12761326
VarTemplateDecl::getPartialSpecializations() const {
1277-
LoadLazySpecializations();
1327+
LoadLazySpecializations(/*PartialOnly = */ true);
12781328
return getCommonPtr()->PartialSpecializations;
12791329
}
12801330

@@ -1288,12 +1338,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
12881338
VarTemplateSpecializationDecl *
12891339
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
12901340
void *&InsertPos) {
1291-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
1341+
auto *Common = getCommonPtr();
1342+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
12921343
}
12931344

12941345
void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
12951346
void *InsertPos) {
1296-
addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos);
1347+
auto *Common = getCommonPtr();
1348+
addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos);
12971349
}
12981350

12991351
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
@@ -7640,14 +7640,23 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
76407640
}
76417641
}
76427642

7643-
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
7644-
CTSD->getSpecializedTemplate()->LoadLazySpecializations();
7645-
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
7646-
VTSD->getSpecializedTemplate()->LoadLazySpecializations();
7647-
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7648-
if (auto *Template = FD->getPrimaryTemplate())
7649-
Template->LoadLazySpecializations();
7650-
}
7643+
RedeclarableTemplateDecl *Template = nullptr;
7644+
ArrayRef<TemplateArgument> Args;
7645+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
7646+
Template = CTSD->getSpecializedTemplate();
7647+
Args = CTSD->getTemplateArgs().asArray();
7648+
} else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
7649+
Template = VTSD->getSpecializedTemplate();
7650+
Args = VTSD->getTemplateArgs().asArray();
7651+
} else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7652+
if (auto *Tmplt = FD->getPrimaryTemplate()) {
7653+
Template = Tmplt;
7654+
Args = FD->getTemplateSpecializationArgs()->asArray();
7655+
}
7656+
}
7657+
7658+
if (Template)
7659+
Template->loadLazySpecializationsImpl(Args);
76517660
}
76527661

76537662
CXXCtorInitializer **

0 commit comments

Comments
 (0)