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/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 86b5817..7683d5a 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1806,6 +1806,12 @@
     return const_cast<FunctionDecl *>(Function);
   }
 
+  if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) {
+    while (FunTmpl->getPreviousDeclaration())
+      FunTmpl = FunTmpl->getPreviousDeclaration();
+    return FunTmpl;
+  }
+  
   if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
     while (Var->getPreviousDeclaration())
       Var = Var->getPreviousDeclaration();
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 725b066..e25fe90 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -372,11 +372,6 @@
 
   C.Deallocate(ParamInfo);
 
-  if (FunctionTemplateSpecializationInfo *Info 
-        = TemplateOrSpecialization
-            .dyn_cast<FunctionTemplateSpecializationInfo*>())
-    C.Deallocate(Info);
-  
   Decl::Destroy(C);
 }
 
@@ -564,6 +559,18 @@
   return false;
 }
 
+void 
+FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
+  PreviousDeclaration = PrevDecl;
+  
+  if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
+    FunctionTemplateDecl *PrevFunTmpl 
+      = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
+    assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
+    FunTmpl->setPreviousDeclaration(PrevFunTmpl);
+  }
+}
+
 /// getOverloadedOperator - Which C++ overloaded operator this
 /// function represents, if any.
 OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
@@ -595,15 +602,21 @@
 void 
 FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
                                                 FunctionTemplateDecl *Template,
-                                     const TemplateArgumentList *TemplateArgs) {
+                                     const TemplateArgumentList *TemplateArgs,
+                                                void *InsertPos) {
   FunctionTemplateSpecializationInfo *Info 
     = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
   if (!Info)
     Info = new (Context) FunctionTemplateSpecializationInfo;
   
+  Info->Function = this;
   Info->Template = Template;
   Info->TemplateArguments = TemplateArgs;
   TemplateOrSpecialization = Info;
+  
+  // Insert this function template specialization into the set of known
+  // function template specialiations.
+  Template->getSpecializations().InsertNode(Info, InsertPos);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 165672d..f1bd1b6 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -81,11 +81,36 @@
                                                    DeclContext *DC,
                                                    SourceLocation L,
                                                    DeclarationName Name,
-                                                   TemplateParameterList *Params,
+                                               TemplateParameterList *Params,
                                                    NamedDecl *Decl) {
   return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
 }
 
+void FunctionTemplateDecl::Destroy(ASTContext &C) {
+  if (Common *CommonPtr = CommonOrPrev.dyn_cast<Common*>()) {
+    for (llvm::FoldingSet<FunctionTemplateSpecializationInfo>::iterator
+              Spec = CommonPtr->Specializations.begin(),
+           SpecEnd = CommonPtr->Specializations.end();
+         Spec != SpecEnd; ++Spec)
+      C.Deallocate(&*Spec);
+  }
+  
+  Decl::Destroy(C);
+}
+
+FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() {
+  // Find the first declaration of this function template.
+  FunctionTemplateDecl *First = this;
+  while (First->getPreviousDeclaration())
+    First = First->getPreviousDeclaration();
+  
+  if (First->CommonOrPrev.isNull()) {
+    // FIXME: Allocate with the ASTContext
+    First->CommonOrPrev = new Common;
+  }
+  return First->CommonOrPrev.get<Common*>();
+}
+
 //===----------------------------------------------------------------------===//
 // ClassTemplateDecl Implementation
 //===----------------------------------------------------------------------===//
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index a823248..acd90e2 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1500,6 +1500,8 @@
     break;
     // No code generation needed.
   case Decl::Using:
+  case Decl::ClassTemplate:
+  case Decl::FunctionTemplate:
     break;
   case Decl::CXXConstructor:
     EmitCXXConstructors(cast<CXXConstructorDecl>(D));
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;
 }