From a3fe12dc58aa2a0dd7292d748b7c104225f863ba Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 10 Dec 2020 16:49:27 -0800 Subject: [PATCH] Ensure that we don't leave behind "InstantiatingSpecialization" entries after destroying an InstantiatingTemplate object. This previously caused us to (silently!) bail out of class template instantiation, thinking we'd produced an error, in some corner cases. --- clang/lib/Sema/Sema.cpp | 3 ++ clang/lib/Sema/SemaTemplateInstantiate.cpp | 31 ++++++++++--------- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 +++ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 456daab7e032..829ab2253614 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -390,6 +390,9 @@ void Sema::Initialize() { } Sema::~Sema() { + assert(InstantiatingSpecializations.empty() && + "failed to clean up an InstantiatingTemplate?"); + if (VisContext) FreeVisContext(); // Kill all the active scopes. diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index e8e34c33e37b..39ea9e06e7b1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -261,7 +261,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( AlreadyInstantiating = !Inst.Entity ? false : !SemaRef.InstantiatingSpecializations - .insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind)) + .insert({Inst.Entity->getCanonicalDecl(), Inst.Kind}) .second; atTemplateBegin(SemaRef.TemplateInstCallbacks, SemaRef, Inst); } @@ -480,7 +480,7 @@ void Sema::InstantiatingTemplate::Clear() { auto &Active = SemaRef.CodeSynthesisContexts.back(); if (Active.Entity) SemaRef.InstantiatingSpecializations.erase( - std::make_pair(Active.Entity, Active.Kind)); + {Active.Entity->getCanonicalDecl(), Active.Kind}); } atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, @@ -3037,14 +3037,16 @@ bool Sema::usesPartialOrExplicitSpecialization( /// Get the instantiation pattern to use to instantiate the definition of a /// given ClassTemplateSpecializationDecl (either the pattern of the primary /// template or of a partial specialization). -static CXXRecordDecl * +static ActionResult getPatternForClassTemplateSpecialization( Sema &S, SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, - TemplateSpecializationKind TSK, bool Complain) { + TemplateSpecializationKind TSK) { Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec); - if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) - return nullptr; + if (Inst.isInvalid()) + return {/*Invalid=*/true}; + if (Inst.isAlreadyInstantiating()) + return {/*Invalid=*/false}; llvm::PointerUnion @@ -3141,7 +3143,7 @@ getPatternForClassTemplateSpecialization( << S.getTemplateArgumentBindingsText( P->Partial->getTemplateParameters(), *P->Args); - return nullptr; + return {/*Invalid=*/true}; } } @@ -3192,14 +3194,15 @@ bool Sema::InstantiateClassTemplateSpecialization( if (ClassTemplateSpec->isInvalidDecl()) return true; - CXXRecordDecl *Pattern = getPatternForClassTemplateSpecialization( - *this, PointOfInstantiation, ClassTemplateSpec, TSK, Complain); - if (!Pattern) - return true; + ActionResult Pattern = + getPatternForClassTemplateSpecialization(*this, PointOfInstantiation, + ClassTemplateSpec, TSK); + if (!Pattern.isUsable()) + return Pattern.isInvalid(); - return InstantiateClass(PointOfInstantiation, ClassTemplateSpec, Pattern, - getTemplateInstantiationArgs(ClassTemplateSpec), TSK, - Complain); + return InstantiateClass( + PointOfInstantiation, ClassTemplateSpec, Pattern.get(), + getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain); } /// Instantiates the definitions of all of the member diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9db4f23d7296..d3d6df5e0064 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4521,6 +4521,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, // into a template instantiation for this specific function template // specialization, which is not a SFINAE context, so that we diagnose any // further errors in the declaration itself. + // + // FIXME: This is a hack. typedef Sema::CodeSynthesisContext ActiveInstType; ActiveInstType &ActiveInst = SemaRef.CodeSynthesisContexts.back(); if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution || @@ -4530,6 +4532,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, assert(FunTmpl->getTemplatedDecl() == Tmpl && "Deduction from the wrong function template?"); (void) FunTmpl; + SemaRef.InstantiatingSpecializations.erase( + {ActiveInst.Entity->getCanonicalDecl(), ActiveInst.Kind}); atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = New;