diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-08-27 16:57:43 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-08-27 16:57:43 +0000 |
commit | d60e105e6d1624da647ef7dd35a9cf6fad1b763e (patch) | |
tree | c96598344ed8cf15681c7b8987323cf861547667 | |
parent | 19377389530101d583955537729e8889d487d59e (diff) |
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<typename T>
struct X {
template<typename U> void f(T, U);
};
When we instantiate X<int>, we now instantiate the declaration
X<int>::f, which looks like this:
template<typename U> void X<int>::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
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 37 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 71 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-member-template.cpp | 22 |
4 files changed, 123 insertions, 10 deletions
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<FunctionTemplateSpecializationInfo> 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 <typename T> + /// struct X { + /// template <typename U> void f(); + /// }; + /// \endcode + /// + /// X<int>::A<float> is a CXXMethodDecl (whose parent is X<int>, a + /// ClassTemplateSpecializationDecl) for which getPrimaryTemplate() will + /// return X<int>::f, a FunctionTemplateDecl (whose parent is again + /// X<int>) for which getInstantiatedFromMemberTemplate() will return + /// X<T>::f, a FunctionTemplateDecl (whose parent is X<T>, 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<CXXMethodDecl>(D->getTemplatedDecl())); + CXXMethodDecl *InstMethod + = cast_or_null<CXXMethodDecl>( + VisitCXXMethodDecl(cast<CXXMethodDecl>(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<typename T> + // struct X { + // template<typename U> void f(T, U); + // }; + // + // X<int> x; + // + // We are instantiating the member template "f" within X<int>, 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<typename T> +struct X0 { + template<typename U> T f0(U); + template<typename U> U& f1(T*, U); // expected-error{{pointer to a reference}} \ + // expected-note{{candidate}} +}; + +X0<int> x0i; +X0<void> x0v; +X0<int&> x0ir; // expected-note{{instantiation}} + +void test_X0(int *ip, double *dp) { + X0<int> xi; + int i1 = xi.f0(ip); + double *&dpr = xi.f1(ip, dp); + xi.f1(dp, dp); // expected-error{{no matching}} + + X0<void> xv; + double *&dpr2 = xv.f1(ip, dp); +} |