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
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 5e91789..42fc1f8 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -48,13 +48,15 @@
     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::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 @@
   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 @@
   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 @@
                                    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 @@
 
   NamedDecl *PrevDecl = 0;
   
-  if (!FunctionTemplate) {
+  if (!FunctionTemplate || TemplateParams) {
     PrevDecl = SemaRef.LookupQualifiedName(Owner, Name, 
                                            Sema::LookupOrdinaryName, true);
   
@@ -579,7 +632,7 @@
       PrevDecl = 0;
   }
 
-  if (FunctionTemplate)
+  if (FunctionTemplate && !TemplateParams)
     // Record this function template specialization.
     Method->setFunctionTemplateSpecialization(SemaRef.Context,
                                               FunctionTemplate,