From d60e105e6d1624da647ef7dd35a9cf6fad1b763e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 27 Aug 2009 16:57:43 +0000 Subject: [PATCH] Implement instantiation of the declarations of member function templates within class templates, producing a member function template of a class template specialization. If you can parse that, I'm sorry. Example: template struct X { template void f(T, U); }; When we instantiate X, we now instantiate the declaration X::f, which looks like this: template void X::f(int, U); The path this takes through TemplateDeclInstantiator::VisitCXXMethodDecl is convoluted and ugly, but I don't know how to improve it yet. I'm resting my hopes on the multi-level substitution required to instantiate definitions of nested templates, which may simplify this code as well. More testing to come... git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80252 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclTemplate.h | 37 ++++++++++ lib/Sema/SemaDecl.cpp | 3 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 71 ++++++++++++++++--- .../instantiate-member-template.cpp | 22 ++++++ 4 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 test/SemaTemplate/instantiate-member-template.cpp diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index ac03a9ea31..fc1c4ddcc1 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -552,9 +552,15 @@ protected: /// \brief Data that is common to all of the declarations of a given /// function template. struct Common { + Common() : InstantiatedFromMember(0) { } + /// \brief The function template specializations for this function /// template, including explicit specializations and instantiations. llvm::FoldingSet Specializations; + + /// \brief The member function template from which this was most + /// directly instantiated (or null). + FunctionTemplateDecl *InstantiatedFromMember; }; /// \brief A pointer to the previous declaration (if this is a redeclaration) @@ -606,6 +612,37 @@ public: virtual FunctionTemplateDecl *getCanonicalDecl(); + /// \brief Retrieve the member function template that this function template + /// was instantiated from. + /// + /// This routine will return non-NULL for member function templates of + /// class templates. For example, given: + /// + /// \code + /// template + /// struct X { + /// template void f(); + /// }; + /// \endcode + /// + /// X::A is a CXXMethodDecl (whose parent is X, a + /// ClassTemplateSpecializationDecl) for which getPrimaryTemplate() will + /// return X::f, a FunctionTemplateDecl (whose parent is again + /// X) for which getInstantiatedFromMemberTemplate() will return + /// X::f, a FunctionTemplateDecl (whose parent is X, a + /// ClassTemplateDecl). + /// + /// \returns NULL if this is not an instantiation of a member function + /// template. + FunctionTemplateDecl *getInstantiatedFromMemberTemplate() { + return getCommonPtr()->InstantiatedFromMember; + } + + void setInstantiatedFromMemberTemplate(FunctionTemplateDecl *FTD) { + assert(!getCommonPtr()->InstantiatedFromMember); + getCommonPtr()->InstantiatedFromMember = FTD; + } + /// Create a template function node. static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5f834dc500..045c12aab5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2534,10 +2534,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (CheckTemplateDeclScope(S, TemplateParams)) return 0; - FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext, + FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, NewFD->getLocation(), Name, TemplateParams, NewFD); + FunctionTemplate->setLexicalDeclContext(CurContext); NewFD->setDescribedFunctionTemplate(FunctionTemplate); } else { // FIXME: Handle function template specializations diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 5e91789083..42fc1f8165 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -48,13 +48,15 @@ namespace { Decl *VisitFriendClassDecl(FriendClassDecl *D); Decl *VisitFunctionDecl(FunctionDecl *D); Decl *VisitCXXRecordDecl(CXXRecordDecl *D); - Decl *VisitCXXMethodDecl(CXXMethodDecl *D); + Decl *VisitCXXMethodDecl(CXXMethodDecl *D, + TemplateParameterList *TemplateParams = 0); Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D); Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); Decl *VisitCXXConversionDecl(CXXConversionDecl *D); ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D); Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D); Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); + Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); // Base case. FIXME: Remove once we can instantiate everything. @@ -356,7 +358,8 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); - if (!InstParams) return NULL; + if (!InstParams) + return NULL; CXXRecordDecl *Pattern = D->getTemplatedDecl(); CXXRecordDecl *RecordInst @@ -375,6 +378,32 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { return Inst; } +Decl * +TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return NULL; + + // FIXME: Handle instantiation of nested function templates that aren't + // member function templates. This could happen inside a FriendDecl. + assert(isa(D->getTemplatedDecl())); + CXXMethodDecl *InstMethod + = cast_or_null( + VisitCXXMethodDecl(cast(D->getTemplatedDecl()), + InstParams)); + if (!InstMethod) + return 0; + + // Link the instantiated function template declaration to the function + // template from which it was instantiated. + FunctionTemplateDecl *InstTemplate = InstMethod->getDescribedFunctionTemplate(); + assert(InstTemplate && "VisitCXXMethodDecl didn't create a template!"); + InstTemplate->setInstantiatedFromMemberTemplate(D); + Owner->addDecl(InstTemplate); + return InstTemplate; +} + Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { CXXRecordDecl *PrevDecl = 0; if (D->isInjectedClassName()) @@ -481,12 +510,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { return Function; } -Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { - // Check whether there is already a function template specialization for - // this declaration. +Decl * +TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, + TemplateParameterList *TemplateParams) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); void *InsertPos = 0; - if (FunctionTemplate) { + if (FunctionTemplate && !TemplateParams) { + // We are creating a function template specialization from a function + // template. Check whether there is already a function template + // specialization for this particular set of template arguments. llvm::FoldingSetNodeID ID; FunctionTemplateSpecializationInfo::Profile(ID, TemplateArgs.getFlatArgumentList(), @@ -548,7 +580,28 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { D->isStatic(), D->isInline()); } - if (!FunctionTemplate) + if (TemplateParams) { + // Our resulting instantiation is actually a function template, since we + // are substituting only the outer template parameters. For example, given + // + // template + // struct X { + // template void f(T, U); + // }; + // + // X x; + // + // We are instantiating the member template "f" within X, which means + // substituting int for T, but leaving "f" as a member function template. + // Build the function template itself. + FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Record, + Method->getLocation(), + Method->getDeclName(), + TemplateParams, Method); + if (D->isOutOfLine()) + FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + Method->setDescribedFunctionTemplate(FunctionTemplate); + } else if (!FunctionTemplate) Method->setInstantiationOfMemberFunction(D); // If we are instantiating a member function defined @@ -567,7 +620,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { NamedDecl *PrevDecl = 0; - if (!FunctionTemplate) { + if (!FunctionTemplate || TemplateParams) { PrevDecl = SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true); @@ -579,7 +632,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { PrevDecl = 0; } - if (FunctionTemplate) + if (FunctionTemplate && !TemplateParams) // Record this function template specialization. Method->setFunctionTemplateSpecialization(SemaRef.Context, FunctionTemplate, diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp new file mode 100644 index 0000000000..959e5c157a --- /dev/null +++ b/test/SemaTemplate/instantiate-member-template.cpp @@ -0,0 +1,22 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template +struct X0 { + template T f0(U); + template U& f1(T*, U); // expected-error{{pointer to a reference}} \ + // expected-note{{candidate}} +}; + +X0 x0i; +X0 x0v; +X0 x0ir; // expected-note{{instantiation}} + +void test_X0(int *ip, double *dp) { + X0 xi; + int i1 = xi.f0(ip); + double *&dpr = xi.f1(ip, dp); + xi.f1(dp, dp); // expected-error{{no matching}} + + X0 xv; + double *&dpr2 = xv.f1(ip, dp); +} -- 2.50.1