From 2b0749a4f8965d0205bf77322db150c13c39e3be Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 25 Mar 2010 15:38:42 +0000 Subject: [PATCH] Improve our handling of local instantiation scopes in two related ways: - When substituting template arguments as part of template argument deduction, introduce a new local instantiation scope. - When substituting into a function prototype type, introduce a new "temporary" local instantiation scope that merges with its outer scope but also keeps track of any additions it makes, removing them when we exit that scope. Fixes PR6700, where we were getting too much mixing of local instantiation scopes due to template argument deduction that substituted results into function types. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99509 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 27 ++++++++++++++++--- lib/Sema/SemaTemplateDeduction.cpp | 12 ++++----- lib/Sema/SemaTemplateInstantiate.cpp | 7 +++-- .../instantiate-function-params.cpp | 11 ++++++++ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index ba6d38f849..7e2e614396 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3487,15 +3487,27 @@ public: /// \brief Whether we have already exited this scope. bool Exited; + /// \brief Whether this scope is temporary, meaning that we should + /// remove any additions we make once we exit this + /// scope. Temporary scopes are always combined with their outer + /// scopes. + bool Temporary; + + /// \brief List of the declarations that we have added into this + /// temporary scope. They will be removed when we exit the + /// temporary scope. + llvm::SmallVector AddedTemporaryDecls; + // This class is non-copyable LocalInstantiationScope(const LocalInstantiationScope &); LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: - LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false, + bool Temporary = false) : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), - Exited(false) { - if (!CombineWithOuterScope) + Exited(false), Temporary(Temporary) { + if (!CombineWithOuterScope && !Temporary) SemaRef.CurrentInstantiationScope = this; else assert(SemaRef.CurrentInstantiationScope && @@ -3503,8 +3515,11 @@ public: } ~LocalInstantiationScope() { - if (!Exited) + if (!Exited) { SemaRef.CurrentInstantiationScope = Outer; + for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I) + LocalDecls.erase(AddedTemporaryDecls[I]); + } } /// \brief Exit this local instantiation scope early. @@ -3537,6 +3552,10 @@ public: void InstantiatedLocal(const Decl *D, Decl *Inst) { Decl *&Stored = LocalDecls[D]; assert((!Stored || Stored == Inst) && "Already instantiated this local"); + + if (Temporary && !Stored) + AddedTemporaryDecls.push_back(D); + Stored = Inst; } }; diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 326519d3a3..3a8ed50894 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -987,13 +987,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Decl *Param = const_cast( Partial->getTemplateParameters()->getParam(I)); - if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) - Info.Param = TTP; - else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast(Param)) - Info.Param = NTTP; - else - Info.Param = cast(Param); + Info.Param = makeTemplateParameter(Param); return TDK_Incomplete; } @@ -1010,6 +1004,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // verify that the instantiated template arguments are both valid // and are equivalent to the template arguments originally provided // to the class template. + Sema::LocalInstantiationScope InstScope(*this); ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); const TemplateArgumentLoc *PartialTemplateArgs = Partial->getTemplateArgsAsWritten(); @@ -1458,6 +1453,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // The types of the parameters from which we will perform template argument // deduction. + Sema::LocalInstantiationScope InstScope(*this); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); llvm::SmallVector Deduced; @@ -1612,6 +1608,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType FunctionType = Function->getType(); // Substitute any explicit template arguments. + Sema::LocalInstantiationScope InstScope(*this); llvm::SmallVector Deduced; llvm::SmallVector ParamTypes; if (ExplicitTemplateArgs) { @@ -1739,6 +1736,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // modulo the various allowed differences. // Finish template argument deduction. + Sema::LocalInstantiationScope InstScope(*this); FunctionDecl *Spec = 0; TemplateDeductionResult Result = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index ac1bf7219c..89a660c79f 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -873,8 +873,11 @@ TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL, llvm::SmallVectorImpl &PTypes, llvm::SmallVectorImpl &PVars) { // Create a local instantiation scope for the parameters. - Sema::LocalInstantiationScope - Scope(SemaRef, SemaRef.CurrentInstantiationScope != 0); + // FIXME: When we implement the C++0x late-specified return type, + // we will need to move this scope out to the function type itself. + bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0); + Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope, + IsTemporaryScope); if (TreeTransform:: TransformFunctionTypeParams(TL, PTypes, PVars)) diff --git a/test/SemaTemplate/instantiate-function-params.cpp b/test/SemaTemplate/instantiate-function-params.cpp index a574dbb787..dfba14a97c 100644 --- a/test/SemaTemplate/instantiate-function-params.cpp +++ b/test/SemaTemplate/instantiate-function-params.cpp @@ -31,3 +31,14 @@ template < typename TT > struct ForwardIterator : I }; typedef instantiate< &requirement_ x)>::failed> boost_concept_checkX; // expected-error{{no member named}} \ // expected-note 6{{in instantiation}} + +template struct X0 { }; +template struct X0 { }; + +template +void instF0(X0 x0a, X0 x0b) { + X0 x0c; + X0 x0d; +} + +template void instF0(X0, X0); -- 2.40.0