Skip to content

Commit be1c83f

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

File tree

7 files changed

+249
-70
lines changed

7 files changed

+249
-70
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+
GlobalDeclID DeclID = GlobalDeclID();
738+
unsigned ODRHash = ~0U;
739+
bool IsPartial = false;
740+
LazySpecializationInfo(GlobalDeclID 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-
GlobalDeclID *LazySpecializations = nullptr;
828+
LazySpecializationInfo *LazySpecializations = nullptr;
801829

802830
/// The set of "injected" template arguments used within this
803831
/// template.
@@ -2284,7 +2312,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
22842312
friend class TemplateDeclInstantiator;
22852313

22862314
/// Load any lazily-loaded specializations from the external source.
2287-
void LoadLazySpecializations() const;
2315+
void LoadLazySpecializations(bool OnlyPartial = false) const;
22882316

22892317
/// Get the underlying class declarations of the template.
22902318
CXXRecordDecl *getTemplatedDecl() const {
@@ -3056,7 +3084,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
30563084
friend class ASTDeclWriter;
30573085

30583086
/// Load any lazily-loaded specializations from the external source.
3059-
void LoadLazySpecializations() const;
3087+
void LoadLazySpecializations(bool OnlyPartial = false) const;
30603088

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

clang/lib/AST/DeclTemplate.cpp

Lines changed: 77 additions & 23 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,17 +333,46 @@ 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-
GlobalDeclID *Specs = CommonBasePtr->LazySpecializations;
341-
CommonBasePtr->LazySpecializations = nullptr;
342-
unsigned SpecSize = (*Specs++).get();
343-
for (unsigned I = 0; I != SpecSize; ++I)
344-
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
341+
if (auto *Specs = CommonBasePtr->LazySpecializations) {
342+
if (!OnlyPartial)
343+
CommonBasePtr->LazySpecializations = nullptr;
344+
unsigned N = Specs[0].DeclID.get();
345+
for (unsigned I = 0; I != N; ++I) {
346+
// Skip over already loaded specializations.
347+
if (!Specs[I+1].ODRHash)
348+
continue;
349+
if (!OnlyPartial || Specs[I+1].IsPartial)
350+
(void)loadLazySpecializationImpl(Specs[I+1]);
351+
}
352+
}
353+
}
354+
355+
Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl(
356+
LazySpecializationInfo &LazySpecInfo) const {
357+
GlobalDeclID ID = LazySpecInfo.DeclID;
358+
assert(ID.isValid() && "Loading already loaded specialization!");
359+
// Note that we loaded the specialization.
360+
LazySpecInfo.DeclID = GlobalDeclID();
361+
LazySpecInfo.ODRHash = LazySpecInfo.IsPartial = 0;
362+
return getASTContext().getExternalSource()->GetExternalDecl(ID);
363+
}
364+
365+
void
366+
RedeclarableTemplateDecl::loadLazySpecializationsImpl(ArrayRef<TemplateArgument>
367+
Args,
368+
TemplateParameterList *TPL) const {
369+
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
370+
if (auto *Specs = CommonBasePtr->LazySpecializations) {
371+
unsigned Hash = TemplateArgumentList::ComputeODRHash(Args);
372+
unsigned N = Specs[0].DeclID.get();
373+
for (uint32_t I = 0; I != N; ++I)
374+
if (Specs[I+1].ODRHash && Specs[I+1].ODRHash == Hash)
375+
(void)loadLazySpecializationImpl(Specs[I+1]);
345376
}
346377
}
347378

@@ -352,6 +383,8 @@ RedeclarableTemplateDecl::findSpecializationImpl(
352383
ProfileArguments&&... ProfileArgs) {
353384
using SETraits = SpecEntryTraits<EntryType>;
354385

386+
loadLazySpecializationsImpl(std::forward<ProfileArguments>(ProfileArgs)...);
387+
355388
llvm::FoldingSetNodeID ID;
356389
EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
357390
getASTContext());
@@ -367,10 +400,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
367400

368401
if (InsertPos) {
369402
#ifndef NDEBUG
403+
auto Args = SETraits::getTemplateArgs(Entry);
404+
// Due to hash collisions, it can happen that we load another template
405+
// specialization with the same hash. This is fine, as long as the next
406+
// call to findSpecializationImpl does not find a matching Decl for the
407+
// template arguments.
408+
loadLazySpecializationsImpl(Args);
370409
void *CorrectInsertPos;
371-
assert(!findSpecializationImpl(Specializations,
372-
CorrectInsertPos,
373-
SETraits::getTemplateArgs(Entry)) &&
410+
assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) &&
374411
InsertPos == CorrectInsertPos &&
375412
"given incorrect InsertPos for specialization");
376413
#endif
@@ -444,12 +481,14 @@ FunctionTemplateDecl::getSpecializations() const {
444481
FunctionDecl *
445482
FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
446483
void *&InsertPos) {
447-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
484+
auto *Common = getCommonPtr();
485+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
448486
}
449487

450488
void FunctionTemplateDecl::addSpecialization(
451489
FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
452-
addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info,
490+
auto *Common = getCommonPtr();
491+
addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info,
453492
InsertPos);
454493
}
455494

@@ -509,8 +548,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
509548
DeclarationName(), nullptr, nullptr);
510549
}
511550

512-
void ClassTemplateDecl::LoadLazySpecializations() const {
513-
loadLazySpecializationsImpl();
551+
void ClassTemplateDecl::LoadLazySpecializations(
552+
bool OnlyPartial/*=false*/) const {
553+
loadLazySpecializationsImpl(OnlyPartial);
514554
}
515555

516556
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
@@ -521,7 +561,7 @@ ClassTemplateDecl::getSpecializations() const {
521561

522562
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
523563
ClassTemplateDecl::getPartialSpecializations() const {
524-
LoadLazySpecializations();
564+
LoadLazySpecializations(/*PartialOnly = */ true);
525565
return getCommonPtr()->PartialSpecializations;
526566
}
527567

@@ -535,12 +575,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
535575
ClassTemplateSpecializationDecl *
536576
ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
537577
void *&InsertPos) {
538-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
578+
auto *Common = getCommonPtr();
579+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
539580
}
540581

541582
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
542583
void *InsertPos) {
543-
addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos);
584+
auto *Common = getCommonPtr();
585+
addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D,
586+
InsertPos);
544587
}
545588

546589
ClassTemplatePartialSpecializationDecl *
@@ -882,6 +925,14 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
882925
return new (Mem) TemplateArgumentList(Args);
883926
}
884927

928+
unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) {
929+
ODRHash Hasher;
930+
for (TemplateArgument TA : Args)
931+
Hasher.AddTemplateArgument(TA);
932+
933+
return Hasher.CalculateHash();
934+
}
935+
885936
FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
886937
ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
887938
TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs,
@@ -1223,8 +1274,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
12231274
DeclarationName(), nullptr, nullptr);
12241275
}
12251276

1226-
void VarTemplateDecl::LoadLazySpecializations() const {
1227-
loadLazySpecializationsImpl();
1277+
void VarTemplateDecl::LoadLazySpecializations(
1278+
bool OnlyPartial/*=false*/) const {
1279+
loadLazySpecializationsImpl(OnlyPartial);
12281280
}
12291281

12301282
llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
@@ -1235,7 +1287,7 @@ VarTemplateDecl::getSpecializations() const {
12351287

12361288
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
12371289
VarTemplateDecl::getPartialSpecializations() const {
1238-
LoadLazySpecializations();
1290+
LoadLazySpecializations(/*PartialOnly = */ true);
12391291
return getCommonPtr()->PartialSpecializations;
12401292
}
12411293

@@ -1249,12 +1301,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
12491301
VarTemplateSpecializationDecl *
12501302
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
12511303
void *&InsertPos) {
1252-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
1304+
auto *Common = getCommonPtr();
1305+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
12531306
}
12541307

12551308
void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
12561309
void *InsertPos) {
1257-
addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos);
1310+
auto *Common = getCommonPtr();
1311+
addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos);
12581312
}
12591313

12601314
VarTemplatePartialSpecializationDecl *

clang/lib/AST/ODRHash.cpp

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

823838
namespace {

clang/lib/Serialization/ASTReader.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7566,14 +7566,23 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
75667566
}
75677567
}
75687568

7569-
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
7570-
CTSD->getSpecializedTemplate()->LoadLazySpecializations();
7571-
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
7572-
VTSD->getSpecializedTemplate()->LoadLazySpecializations();
7573-
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7574-
if (auto *Template = FD->getPrimaryTemplate())
7575-
Template->LoadLazySpecializations();
7576-
}
7569+
RedeclarableTemplateDecl *Template = nullptr;
7570+
ArrayRef<TemplateArgument> Args;
7571+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
7572+
Template = CTSD->getSpecializedTemplate();
7573+
Args = CTSD->getTemplateArgs().asArray();
7574+
} else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
7575+
Template = VTSD->getSpecializedTemplate();
7576+
Args = VTSD->getTemplateArgs().asArray();
7577+
} else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7578+
if (auto *Tmplt = FD->getPrimaryTemplate()) {
7579+
Template = Tmplt;
7580+
Args = FD->getTemplateSpecializationArgs()->asArray();
7581+
}
7582+
}
7583+
7584+
if (Template)
7585+
Template->loadLazySpecializationsImpl(Args);
75777586
}
75787587

75797588
CXXCtorInitializer **

0 commit comments

Comments
 (0)