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 {
443478FunctionDecl *
444479FunctionTemplateDecl::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
449485void 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
515553llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
@@ -520,7 +558,7 @@ ClassTemplateDecl::getSpecializations() const {
520558
521559llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
522560ClassTemplateDecl::getPartialSpecializations () const {
523- LoadLazySpecializations ();
561+ LoadLazySpecializations (/* PartialOnly = */ true );
524562 return getCommonPtr ()->PartialSpecializations ;
525563}
526564
@@ -534,12 +572,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
534572ClassTemplateSpecializationDecl *
535573ClassTemplateDecl::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
540579void 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
545586ClassTemplatePartialSpecializationDecl *
@@ -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+
886935FunctionTemplateSpecializationInfo *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
12321282llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
@@ -1237,7 +1287,7 @@ VarTemplateDecl::getSpecializations() const {
12371287
12381288llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
12391289VarTemplateDecl::getPartialSpecializations () const {
1240- LoadLazySpecializations ();
1290+ LoadLazySpecializations (/* PartialOnly = */ true );
12411291 return getCommonPtr ()->PartialSpecializations ;
12421292}
12431293
@@ -1251,12 +1301,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
12511301VarTemplateSpecializationDecl *
12521302VarTemplateDecl::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
12571308void 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
12621314VarTemplatePartialSpecializationDecl *
0 commit comments