Skip to content

Commit 270cdac

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

File tree

9 files changed

+255
-76
lines changed

9 files changed

+255
-76
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*
@@ -796,7 +824,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
796824
///
797825
/// The first value in the array is the number of specializations/partial
798826
/// specializations that follow.
799-
GlobalDeclID *LazySpecializations = nullptr;
827+
LazySpecializationInfo *LazySpecializations = nullptr;
800828

801829
/// The set of "injected" template arguments used within this
802830
/// template.
@@ -2279,7 +2307,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
22792307
friend class TemplateDeclInstantiator;
22802308

22812309
/// Load any lazily-loaded specializations from the external source.
2282-
void LoadLazySpecializations() const;
2310+
void LoadLazySpecializations(bool OnlyPartial = false) const;
22832311

22842312
/// Get the underlying class declarations of the template.
22852313
CXXRecordDecl *getTemplatedDecl() const {
@@ -3023,7 +3051,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
30233051
friend class ASTDeclWriter;
30243052

30253053
/// Load any lazily-loaded specializations from the external source.
3026-
void LoadLazySpecializations() const;
3054+
void LoadLazySpecializations(bool OnlyPartial = false) const;
30273055

30283056
/// Get the underlying variable declarations of the template.
30293057
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++).getRawValue();
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.getRawValue();
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.getRawValue();
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 *
@@ -897,6 +940,14 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
897940
return new (Mem) TemplateArgumentList(Args);
898941
}
899942

943+
unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) {
944+
ODRHash Hasher;
945+
for (TemplateArgument TA : Args)
946+
Hasher.AddTemplateArgument(TA);
947+
948+
return Hasher.CalculateHash();
949+
}
950+
900951
FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
901952
ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
902953
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
@@ -1262,8 +1313,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
12621313
DeclarationName(), nullptr, nullptr);
12631314
}
12641315

1265-
void VarTemplateDecl::LoadLazySpecializations() const {
1266-
loadLazySpecializationsImpl();
1316+
void VarTemplateDecl::LoadLazySpecializations(
1317+
bool OnlyPartial/*=false*/) const {
1318+
loadLazySpecializationsImpl(OnlyPartial);
12671319
}
12681320

12691321
llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
@@ -1274,7 +1326,7 @@ VarTemplateDecl::getSpecializations() const {
12741326

12751327
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
12761328
VarTemplateDecl::getPartialSpecializations() const {
1277-
LoadLazySpecializations();
1329+
LoadLazySpecializations(/*PartialOnly = */ true);
12781330
return getCommonPtr()->PartialSpecializations;
12791331
}
12801332

@@ -1288,12 +1340,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
12881340
VarTemplateSpecializationDecl *
12891341
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
12901342
void *&InsertPos) {
1291-
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
1343+
auto *Common = getCommonPtr();
1344+
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
12921345
}
12931346

12941347
void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
12951348
void *InsertPos) {
1296-
addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos);
1349+
auto *Common = getCommonPtr();
1350+
addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos);
12971351
}
12981352

12991353
VarTemplatePartialSpecializationDecl *

clang/lib/AST/ODRHash.cpp

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

830845
namespace {

clang/lib/Serialization/ASTReader.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7594,14 +7594,23 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
75947594
}
75957595
}
75967596

7597-
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
7598-
CTSD->getSpecializedTemplate()->LoadLazySpecializations();
7599-
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
7600-
VTSD->getSpecializedTemplate()->LoadLazySpecializations();
7601-
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7602-
if (auto *Template = FD->getPrimaryTemplate())
7603-
Template->LoadLazySpecializations();
7604-
}
7597+
RedeclarableTemplateDecl *Template = nullptr;
7598+
ArrayRef<TemplateArgument> Args;
7599+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
7600+
Template = CTSD->getSpecializedTemplate();
7601+
Args = CTSD->getTemplateArgs().asArray();
7602+
} else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
7603+
Template = VTSD->getSpecializedTemplate();
7604+
Args = VTSD->getTemplateArgs().asArray();
7605+
} else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
7606+
if (auto *Tmplt = FD->getPrimaryTemplate()) {
7607+
Template = Tmplt;
7608+
Args = FD->getTemplateSpecializationArgs()->asArray();
7609+
}
7610+
}
7611+
7612+
if (Template)
7613+
Template->loadLazySpecializationsImpl(Args);
76057614
}
76067615

76077616
CXXCtorInitializer **

0 commit comments

Comments
 (0)