From 9961ce9428a935c33541936e019fc1e810b8c09f Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 8 Jul 2010 18:37:38 +0000 Subject: [PATCH] When performing substitution of template arguments within the body of a template, be sure to include the template arguments from the injected-class-name. Fixes PR7587. llvm-svn: 107895 --- clang/include/clang/AST/DeclTemplate.h | 2 +- clang/lib/AST/DeclTemplate.cpp | 4 +-- clang/lib/Sema/SemaCXXScopeSpec.cpp | 2 +- clang/lib/Sema/SemaExpr.cpp | 7 ++-- clang/lib/Sema/SemaTemplate.cpp | 2 +- clang/lib/Sema/SemaTemplate.h | 31 ++++++++++++----- clang/lib/Sema/SemaTemplateInstantiate.cpp | 12 ++++++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 30 +++++++++++------ .../instantiate-member-template.cpp | 33 +++++++++++++++++++ 9 files changed, 95 insertions(+), 28 deletions(-) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 1fa596cccb24..135dd3ae78d3 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1476,7 +1476,7 @@ public: /// typedef array this_type; // "array" is equivalent to "array" /// }; /// \endcode - QualType getInjectedClassNameSpecialization(ASTContext &Context); + QualType getInjectedClassNameSpecialization(); /// \brief Retrieve the member class template that this class template was /// derived from. diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 9a7bc9105bd5..f00eb0478a75 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -201,7 +201,7 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) { } QualType -ClassTemplateDecl::getInjectedClassNameSpecialization(ASTContext &Context) { +ClassTemplateDecl::getInjectedClassNameSpecialization() { Common *CommonPtr = getCommonPtr(); if (!CommonPtr->InjectedClassNameType.isNull()) return CommonPtr->InjectedClassNameType; @@ -210,7 +210,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization(ASTContext &Context) { // corresponding to template parameter packs should be pack // expansions. We already say that in 14.6.2.1p2, so it would be // better to fix that redundancy. - + ASTContext &Context = getASTContext(); TemplateParameterList *Params = getTemplateParameters(); llvm::SmallVector TemplateArgs; TemplateArgs.reserve(Params->size()); diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 42c346fbe83d..f56573a8de26 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -96,7 +96,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, // injected class name of the named class template, we're entering // into that class template definition. QualType Injected - = ClassTemplate->getInjectedClassNameSpecialization(Context); + = ClassTemplate->getInjectedClassNameSpecialization(); if (Context.hasSameType(Injected, ContextType)) return ClassTemplate->getTemplatedDecl(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 93cec73d0386..66369674f25b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3317,9 +3317,10 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true); - InstantiatingTemplate Inst(*this, CallLoc, Param, - ArgList.getInnermost().getFlatArgumentList(), - ArgList.getInnermost().flat_size()); + std::pair Innermost + = ArgList.getInnermost(); + InstantiatingTemplate Inst(*this, CallLoc, Param, Innermost.first, + Innermost.second); OwningExprResult Result = SubstExpr(UninstExpr, ArgList); if (Result.isInvalid()) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index af1cb50006e1..31823c72eada 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -884,7 +884,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, NewClass->setDescribedClassTemplate(NewTemplate); // Build the type for the class template declaration now. - QualType T = NewTemplate->getInjectedClassNameSpecialization(Context); + QualType T = NewTemplate->getInjectedClassNameSpecialization(); T = Context.getInjectedClassNameType(NewClass, T); assert(T->isDependentType() && "Class template type is not dependent?"); (void)T; diff --git a/clang/lib/Sema/SemaTemplate.h b/clang/lib/Sema/SemaTemplate.h index ca59e2735518..b3f46519ab7f 100644 --- a/clang/lib/Sema/SemaTemplate.h +++ b/clang/lib/Sema/SemaTemplate.h @@ -36,10 +36,14 @@ namespace clang { /// When instantiating X::Y<17>::f, the multi-level template argument /// list will contain a template argument list (int) at depth 0 and a /// template argument list (17) at depth 1. - struct MultiLevelTemplateArgumentList { + class MultiLevelTemplateArgumentList { + public: + typedef std::pair ArgList; + + private: /// \brief The template argument lists, stored from the innermost template /// argument list (first) to the outermost template argument list (last). - llvm::SmallVector TemplateArgumentLists; + llvm::SmallVector TemplateArgumentLists; public: /// \brief Construct an empty set of template argument lists. @@ -48,7 +52,7 @@ namespace clang { /// \brief Construct a single-level template argument list. explicit MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) { - TemplateArgumentLists.push_back(&TemplateArgs); + addOuterTemplateArguments(&TemplateArgs); } /// \brief Determine the number of levels in this template argument @@ -58,8 +62,8 @@ namespace clang { /// \brief Retrieve the template argument at a given depth and index. const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { assert(Depth < TemplateArgumentLists.size()); - assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1]->size()); - return TemplateArgumentLists[getNumLevels() - Depth - 1]->get(Index); + assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].second); + return TemplateArgumentLists[getNumLevels() - Depth - 1].first[Index]; } /// \brief Determine whether there is a non-NULL template argument at the @@ -69,7 +73,7 @@ namespace clang { bool hasTemplateArgument(unsigned Depth, unsigned Index) const { assert(Depth < TemplateArgumentLists.size()); - if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1]->size()) + if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].second) return false; return !(*this)(Depth, Index).isNull(); @@ -78,12 +82,21 @@ namespace clang { /// \brief Add a new outermost level to the multi-level template argument /// list. void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { - TemplateArgumentLists.push_back(TemplateArgs); + TemplateArgumentLists.push_back( + ArgList(TemplateArgs->getFlatArgumentList(), + TemplateArgs->flat_size())); + } + + /// \brief Add a new outmost level to the multi-level template argument + /// list. + void addOuterTemplateArguments(const TemplateArgument *Args, + unsigned NumArgs) { + TemplateArgumentLists.push_back(ArgList(Args, NumArgs)); } /// \brief Retrieve the innermost template argument list. - const TemplateArgumentList &getInnermost() const { - return *TemplateArgumentLists.front(); + const ArgList &getInnermost() const { + return TemplateArgumentLists.front(); } }; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 897acf39ceee..6db0916e4459 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -63,7 +63,8 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Ctx)) { // We're done when we hit an explicit specialization. - if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization) + if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa(Spec)) break; Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); @@ -104,6 +105,15 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, RelativeToPrimary = false; continue; } + } else if (CXXRecordDecl *Rec = dyn_cast(Ctx)) { + if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { + QualType T = ClassTemplate->getInjectedClassNameSpecialization(); + const TemplateSpecializationType *TST + = cast(Context.getCanonicalType(T)); + Result.addOuterTemplateArguments(TST->getArgs(), TST->getNumArgs()); + if (ClassTemplate->isMemberSpecialization()) + break; + } } Ctx = Ctx->getParent(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 853f7c309446..5778a827fcfe 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -820,7 +820,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // Trigger creation of the type for the instantiation. SemaRef.Context.getInjectedClassNameType(RecordInst, - Inst->getInjectedClassNameSpecialization(SemaRef.Context)); + Inst->getInjectedClassNameSpecialization()); // Finish handling of friends. if (isFriend) { @@ -978,9 +978,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, void *InsertPos = 0; if (FunctionTemplate && !TemplateParams) { llvm::FoldingSetNodeID ID; - FunctionTemplateSpecializationInfo::Profile(ID, - TemplateArgs.getInnermost().getFlatArgumentList(), - TemplateArgs.getInnermost().flat_size(), + std::pair Innermost + = TemplateArgs.getInnermost(); + FunctionTemplateSpecializationInfo::Profile(ID, Innermost.first, + Innermost.second, SemaRef.Context); FunctionTemplateSpecializationInfo *Info @@ -1089,8 +1090,12 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } } else if (FunctionTemplate) { // Record this function template specialization. + std::pair Innermost + = TemplateArgs.getInnermost(); Function->setFunctionTemplateSpecialization(FunctionTemplate, - &TemplateArgs.getInnermost(), + new (SemaRef.Context) TemplateArgumentList(SemaRef.Context, + Innermost.first, + Innermost.second), InsertPos); } else if (isFriend && D->isThisDeclarationADefinition()) { // TODO: should we remember this connection regardless of whether @@ -1227,9 +1232,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // template. Check whether there is already a function template // specialization for this particular set of template arguments. llvm::FoldingSetNodeID ID; - FunctionTemplateSpecializationInfo::Profile(ID, - TemplateArgs.getInnermost().getFlatArgumentList(), - TemplateArgs.getInnermost().flat_size(), + std::pair Innermost + = TemplateArgs.getInnermost(); + FunctionTemplateSpecializationInfo::Profile(ID, Innermost.first, + Innermost.second, SemaRef.Context); FunctionTemplateSpecializationInfo *Info @@ -1374,8 +1380,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (FunctionTemplate) { // Record this function template specialization. + std::pair Innermost + = TemplateArgs.getInnermost(); Method->setFunctionTemplateSpecialization(FunctionTemplate, - &TemplateArgs.getInnermost(), + new (SemaRef.Context) TemplateArgumentList(SemaRef.Context, + Innermost.first, + Innermost.second), InsertPos); } else if (!isFriend) { // Record that this is an instantiation of a member function. @@ -2597,7 +2607,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate(); if (ClassTemplate) { - T = ClassTemplate->getInjectedClassNameSpecialization(Context); + T = ClassTemplate->getInjectedClassNameSpecialization(); } else if (ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast(Record)) { ClassTemplate = PartialSpec->getSpecializedTemplate(); diff --git a/clang/test/SemaTemplate/instantiate-member-template.cpp b/clang/test/SemaTemplate/instantiate-member-template.cpp index ae8425e716ee..24a3f317e636 100644 --- a/clang/test/SemaTemplate/instantiate-member-template.cpp +++ b/clang/test/SemaTemplate/instantiate-member-template.cpp @@ -156,3 +156,36 @@ namespace PR6239 { }; } + +namespace PR7587 { + template class X0; + template struct X1; + template class X2; + + template class X3 + { + template< + template class TT, + typename U = typename X1::type + > + struct Inner { + typedef X2::type> > Type; + }; + + const typename Inner::Type minCoeff() const; + }; + + template class X3 + { + template< + template class TT, + typename U = typename X1::type + > + struct Inner { + typedef X2::type> > Type; + }; + + const typename Inner::Type minCoeff() const; + }; + +}