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 {
448483FunctionDecl *
449484FunctionTemplateDecl::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
454490void 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
520558llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
@@ -525,7 +563,7 @@ ClassTemplateDecl::getSpecializations() const {
525563
526564llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
527565ClassTemplateDecl::getPartialSpecializations () const {
528- LoadLazySpecializations ();
566+ LoadLazySpecializations (/* PartialOnly = */ true );
529567 return getCommonPtr ()->PartialSpecializations ;
530568}
531569
@@ -539,12 +577,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
539577ClassTemplateSpecializationDecl *
540578ClassTemplateDecl::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
545584void 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
550591ClassTemplatePartialSpecializationDecl *
@@ -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+
900949FunctionTemplateSpecializationInfo *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
12691319llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
@@ -1274,7 +1324,7 @@ VarTemplateDecl::getSpecializations() const {
12741324
12751325llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
12761326VarTemplateDecl::getPartialSpecializations () const {
1277- LoadLazySpecializations ();
1327+ LoadLazySpecializations (/* PartialOnly = */ true );
12781328 return getCommonPtr ()->PartialSpecializations ;
12791329}
12801330
@@ -1288,12 +1338,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
12881338VarTemplateSpecializationDecl *
12891339VarTemplateDecl::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
12941345void 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
12991351VarTemplatePartialSpecializationDecl *
0 commit comments