Keep track of function template specializations, to eliminate
redundant, implicit instantiations of function templates and provide a
place where we can hang function template specializations.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74454 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 3d909bb..5300385 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1036,14 +1036,22 @@
                          InstantiateDecl(FunctionTemplate->getTemplatedDecl(),
                                          FunctionTemplate->getDeclContext(),
                                          *DeducedArgumentList));
-  
-  if (!Specialization || Trap.hasErrorOccurred())
+  if (!Specialization)
     return TDK_SubstitutionFailure;
+  
+  // If the template argument list is owned by the function template 
+  // specialization, release it.
+  if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList)
+    Info.take();
 
-  // Turn the specialization into an actual function template specialization.
-  Specialization->setFunctionTemplateSpecialization(Context,
-                                                    FunctionTemplate,
-                                                    Info.take());
+  // There may have been an error that did not prevent us from constructing a
+  // declaration. Mark the declaration invalid and return with a substitution
+  // failure.
+  if (Trap.hasErrorOccurred()) {
+    Specialization->setInvalidDecl(true);
+    return TDK_SubstitutionFailure;
+  }
+  
   return TDK_Success;
 }
 
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a05095f..ac0f46e 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -294,7 +294,24 @@
 }
 
 Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
-  // FIXME: Look for existing specializations (explicit or otherwise).
+  // Check whether there is already a function template specialization for
+  // this declaration.
+  FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
+  void *InsertPos = 0;
+  if (FunctionTemplate) {
+    llvm::FoldingSetNodeID ID;
+    FunctionTemplateSpecializationInfo::Profile(ID, 
+                                          TemplateArgs.getFlatArgumentList(),
+                                                TemplateArgs.flat_size());
+    
+    FunctionTemplateSpecializationInfo *Info 
+      = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID, 
+                                                                   InsertPos);
+    
+    // If we already have a function template specialization, return it.
+    if (Info)
+      return Info->Function;
+  }
   
   Sema::LocalInstantiationScope Scope(SemaRef);
   
@@ -325,10 +342,15 @@
   NamedDecl *PrevDecl = 0;
   SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
                                    /*FIXME:*/OverloadableAttrRequired);
-  
 
-  // FIXME: link this to the function template from which it was instantiated.
-  
+  if (FunctionTemplate) {
+    // Record this function template specialization.
+    Function->setFunctionTemplateSpecialization(SemaRef.Context,
+                                                FunctionTemplate,
+                                                &TemplateArgs,
+                                                InsertPos);
+   }
+
   return Function;
 }