/// \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)
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,
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.
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
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())
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(),
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
NamedDecl *PrevDecl = 0;
- if (!FunctionTemplate) {
+ if (!FunctionTemplate || TemplateParams) {
PrevDecl = SemaRef.LookupQualifiedName(Owner, Name,
Sema::LookupOrdinaryName, true);
PrevDecl = 0;
}
- if (FunctionTemplate)
+ if (FunctionTemplate && !TemplateParams)
// Record this function template specialization.
Method->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,