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 {
453488FunctionDecl *
454489FunctionTemplateDecl::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
459495void 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
523561llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
@@ -528,7 +566,7 @@ ClassTemplateDecl::getSpecializations() const {
528566
529567llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
530568ClassTemplateDecl::getPartialSpecializations () const {
531- LoadLazySpecializations ();
569+ LoadLazySpecializations (/* PartialOnly = */ true );
532570 return getCommonPtr ()->PartialSpecializations ;
533571}
534572
@@ -542,12 +580,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
542580ClassTemplateSpecializationDecl *
543581ClassTemplateDecl::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
548587void 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
553594ClassTemplatePartialSpecializationDecl *
@@ -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+
907956FunctionTemplateSpecializationInfo *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
12901340llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
@@ -1295,7 +1345,7 @@ VarTemplateDecl::getSpecializations() const {
12951345
12961346llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
12971347VarTemplateDecl::getPartialSpecializations () const {
1298- LoadLazySpecializations ();
1348+ LoadLazySpecializations (/* PartialOnly = */ true );
12991349 return getCommonPtr ()->PartialSpecializations ;
13001350}
13011351
@@ -1309,12 +1359,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
13091359VarTemplateSpecializationDecl *
13101360VarTemplateDecl::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
13151366void 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
13201372VarTemplatePartialSpecializationDecl *
0 commit comments