Keep track of whether a member function instantiated from a member
function of a class template was implicitly instantiated, explicitly
instantiated (declaration or definition), or explicitly
specialized. The same MemberSpecializationInfo structure will be used
for static data members and member classes as well.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83509 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index fe32c39..a5c9fa4 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -410,6 +410,16 @@
   for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
     (*I)->Destroy(C);
 
+  FunctionTemplateSpecializationInfo *FTSInfo
+    = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
+  if (FTSInfo)
+    C.Deallocate(FTSInfo);
+  
+  MemberSpecializationInfo *MSInfo
+    = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
+  if (MSInfo)
+    C.Deallocate(MSInfo);
+  
   C.Deallocate(ParamInfo);
 
   Decl::Destroy(C);
@@ -670,6 +680,24 @@
     return OO_None;
 }
 
+FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
+  if (MemberSpecializationInfo *Info 
+        = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>())
+    return cast<FunctionDecl>(Info->getInstantiatedFrom());
+  
+  return 0;
+}
+
+void 
+FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD,
+                                               TemplateSpecializationKind TSK) {
+  assert(TemplateOrSpecialization.isNull() && 
+         "Member function is already a specialization");
+  MemberSpecializationInfo *Info 
+    = new (getASTContext()) MemberSpecializationInfo(FD, TSK);
+  TemplateOrSpecialization = Info;
+}
+
 FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
   if (FunctionTemplateSpecializationInfo *Info
         = TemplateOrSpecialization
@@ -727,32 +755,30 @@
 TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
   // For a function template specialization, query the specialization
   // information object.
-  FunctionTemplateSpecializationInfo *Info
+  FunctionTemplateSpecializationInfo *FTSInfo
     = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
-  if (Info)
-    return Info->getTemplateSpecializationKind();
+  if (FTSInfo)
+    return FTSInfo->getTemplateSpecializationKind();
 
-  if (!getInstantiatedFromMemberFunction())
-    return TSK_Undeclared;
-
-  // Find the class template specialization corresponding to this instantiation
-  // of a member function.
-  const DeclContext *Parent = getDeclContext();
-  while (Parent && !isa<ClassTemplateSpecializationDecl>(Parent))
-    Parent = Parent->getParent();
-
-  if (!Parent)
-    return TSK_Undeclared;
-
-  return cast<ClassTemplateSpecializationDecl>(Parent)->getSpecializationKind();
+  MemberSpecializationInfo *MSInfo
+    = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
+  if (MSInfo)
+    return MSInfo->getTemplateSpecializationKind();
+  
+  return TSK_Undeclared;
 }
 
 void
 FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
-  FunctionTemplateSpecializationInfo *Info
-    = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
-  assert(Info && "Not a function template specialization");
-  Info->setTemplateSpecializationKind(TSK);
+  if (FunctionTemplateSpecializationInfo *FTSInfo
+        = TemplateOrSpecialization.dyn_cast<
+                                        FunctionTemplateSpecializationInfo*>())
+    FTSInfo->setTemplateSpecializationKind(TSK);
+  else if (MemberSpecializationInfo *MSInfo
+             = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>())
+    MSInfo->setTemplateSpecializationKind(TSK);
+  else
+    assert(false && "Function cannot have a template specialization kind");
 }
 
 bool FunctionDecl::isOutOfLine() const {
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f3cd2e4..339a084 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3171,10 +3171,13 @@
                                        Instantiation, FD->getLocation(), 
                                        false, TSK_ExplicitSpecialization))
     return true;
+
+  // FIXME: Check for specialization-after-instantiation errors and such.
   
-  // FIXME: Mark the new declaration as a member function specialization.
-  // We may also want to mark the original instantiation as having been
-  // explicitly specialized.
+  // Note that this function is an explicit instantiation of a member function.
+  Instantiation->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
+  FD->setInstantiationOfMemberFunction(FunctionInTemplate, 
+                                       TSK_ExplicitSpecialization);
   
   // Save the caller the trouble of having to figure out which declaration
   // this specialization matches.
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 9c96b33..e0ffca9 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -977,6 +977,8 @@
                                DEnd = Instantiation->decls_end();
        D != DEnd; ++D) {
     if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
+      if (Function->getInstantiatedFromMemberFunction())
+        Function->setTemplateSpecializationKind(TSK);
       if (!Function->getBody() && TSK != TSK_ExplicitInstantiationDeclaration)
         InstantiateFunctionDefinition(PointOfInstantiation, Function);
     } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
@@ -984,14 +986,19 @@
           TSK != TSK_ExplicitInstantiationDeclaration)
         InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
     } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
-      if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) {
-        assert(Record->getInstantiatedFromMemberClass() &&
-               "Missing instantiated-from-template information");
+      if (Record->isInjectedClassName())
+        continue;
+      
+      assert(Record->getInstantiatedFromMemberClass() &&
+             "Missing instantiated-from-template information");
+      if (!Record->getDefinition(Context))
         InstantiateClass(PointOfInstantiation, Record,
                          Record->getInstantiatedFromMemberClass(),
                          TemplateArgs,
                          TSK);
-      }
+      else
+        InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs, 
+                                TSK);
     }
   }
 }
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index fa30365..fcacb4a 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -522,7 +522,7 @@
     if (!Owner->isDependentContext())
       DC->makeDeclVisibleInContext(Function, /* Recoverable = */ false);
 
-    Function->setInstantiationOfMemberFunction(D);
+    Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
   }
 
   if (InitFunctionInstantiation(Function, D))
@@ -637,7 +637,7 @@
       FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
     Method->setDescribedFunctionTemplate(FunctionTemplate);
   } else if (!FunctionTemplate)
-    Method->setInstantiationOfMemberFunction(D);
+    Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
 
   // If we are instantiating a member function defined
   // out-of-line, the instantiation will have the same lexical