Keep track of more information within the template instantiation stack, e.g.,
by distinguishing between substitution that occurs for template
argument deduction vs. explicitly-specifiad template arguments. This
is used both to improve diagnostics and to make sure we only provide
SFINAE in those cases where SFINAE should apply.

In addition, deal with the sticky issue where SFINAE only considers
substitution of template arguments into the *type* of a function
template; we need to issue hard errors beyond this point, as
test/SemaTemplate/operator-template.cpp illustrates.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74651 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 338221e..a6c34e8 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2359,7 +2359,7 @@
   /// \brief A template instantiation that is currently in progress.
   struct ActiveTemplateInstantiation {
     /// \brief The kind of template instantiation we are performing
-    enum {
+    enum InstantiationKind {
       /// We are instantiating a template declaration. The entity is
       /// the declaration we're instantiating (e.g., a CXXRecordDecl).
       TemplateInstantiation,
@@ -2371,13 +2371,16 @@
       /// FIXME: Use a TemplateArgumentList
       DefaultTemplateArgumentInstantiation,
 
-      /// We are performing template argument deduction for a class
-      /// template partial specialization. The Entity is the class
-      /// template partial specialization, and
-      /// TemplateArgs/NumTemplateArgs provides the deduced template
-      /// arguments.
-      /// FIXME: Use a TemplateArgumentList
-      PartialSpecDeductionInstantiation
+      /// We are substituting explicit template arguments provided for 
+      /// a function template. The entity is a FunctionTemplateDecl.
+      ExplicitTemplateArgumentSubstitution,
+      
+      /// We are substituting template argument determined as part of
+      /// template argument deduction for either a class template
+      /// partial specialization or a function template. The
+      /// Entity is either a ClassTemplatePartialSpecializationDecl or
+      /// a FunctionTemplateDecl.
+      DeducedTemplateArgumentSubstitution
     } Kind;
 
     /// \brief The point of instantiation within the source code.
@@ -2411,7 +2414,8 @@
         return true;
 
       case DefaultTemplateArgumentInstantiation:
-      case PartialSpecDeductionInstantiation:
+      case ExplicitTemplateArgumentSubstitution:
+      case DeducedTemplateArgumentSubstitution:
         return X.TemplateArgs == Y.TemplateArgs;
       }
 
@@ -2468,6 +2472,15 @@
                           unsigned NumTemplateArgs,
                           SourceRange InstantiationRange = SourceRange());
 
+    /// \brief Note that we are instantiating a default argument in a
+    /// template-id.
+    InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+                          FunctionTemplateDecl *FunctionTemplate,
+                          const TemplateArgument *TemplateArgs,
+                          unsigned NumTemplateArgs,
+                          ActiveTemplateInstantiation::InstantiationKind Kind,
+                          SourceRange InstantiationRange = SourceRange());
+    
     /// \brief Note that we are instantiating as part of template
     /// argument deduction for a class template partial
     /// specialization.
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index ae0e704..5a0578f 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -939,7 +939,8 @@
     // explicitly-specified template arguments against this function template,
     // and then substitute them into the function parameter types.
     InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), 
-                               FunctionTemplate, Deduced.data(), Deduced.size());
+                               FunctionTemplate, Deduced.data(), Deduced.size(),
+             ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution);
     if (Inst)
       return TDK_InstantiationDepth;
     
@@ -1106,7 +1107,8 @@
   // Enter a new template instantiation context while we instantiate the
   // actual function declaration.
   InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), 
-                             FunctionTemplate, Deduced.data(), Deduced.size());
+                             FunctionTemplate, Deduced.data(), Deduced.size(),
+              ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
   if (Inst)
     return TDK_InstantiationDepth; 
                                   
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 3bc1cf9..6c2dc77 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -100,6 +100,30 @@
 
 Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, 
                                          SourceLocation PointOfInstantiation,
+                                      FunctionTemplateDecl *FunctionTemplate,
+                                        const TemplateArgument *TemplateArgs,
+                                                   unsigned NumTemplateArgs,
+                         ActiveTemplateInstantiation::InstantiationKind Kind,
+                                              SourceRange InstantiationRange)
+: SemaRef(SemaRef) {
+  
+  Invalid = CheckInstantiationDepth(PointOfInstantiation,
+                                    InstantiationRange);
+  if (!Invalid) {
+    ActiveTemplateInstantiation Inst;
+    Inst.Kind = Kind;
+    Inst.PointOfInstantiation = PointOfInstantiation;
+    Inst.Entity = reinterpret_cast<uintptr_t>(FunctionTemplate);
+    Inst.TemplateArgs = TemplateArgs;
+    Inst.NumTemplateArgs = NumTemplateArgs;
+    Inst.InstantiationRange = InstantiationRange;
+    SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+    Invalid = false;
+  }
+}
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, 
+                                         SourceLocation PointOfInstantiation,
                           ClassTemplatePartialSpecializationDecl *PartialSpec,
                                          const TemplateArgument *TemplateArgs,
                                          unsigned NumTemplateArgs,
@@ -111,7 +135,7 @@
   if (!Invalid) {
     ActiveTemplateInstantiation Inst;
     Inst.Kind 
-      = ActiveTemplateInstantiation::PartialSpecDeductionInstantiation;
+      = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
     Inst.PointOfInstantiation = PointOfInstantiation;
     Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
     Inst.TemplateArgs = TemplateArgs;
@@ -148,6 +172,7 @@
 /// \brief Prints the current instantiation stack through a series of
 /// notes.
 void Sema::PrintInstantiationStack() {
+  // FIXME: In all of these cases, we need to show the template arguments
   for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator
          Active = ActiveTemplateInstantiations.rbegin(),
          ActiveEnd = ActiveTemplateInstantiations.rend();
@@ -183,7 +208,7 @@
       TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity);
       std::string TemplateArgsStr
         = TemplateSpecializationType::PrintTemplateArgumentList(
-                                                      Active->TemplateArgs, 
+                                                         Active->TemplateArgs, 
                                                       Active->NumTemplateArgs,
                                                       Context.PrintingPolicy);
       Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
@@ -193,18 +218,31 @@
       break;
     }
 
-    case ActiveTemplateInstantiation::PartialSpecDeductionInstantiation: {
-      ClassTemplatePartialSpecializationDecl *PartialSpec
-        = cast<ClassTemplatePartialSpecializationDecl>((Decl *)Active->Entity);
-      // FIXME: The active template instantiation's template arguments
-      // are interesting, too. We should add something like [with T =
-      // foo, U = bar, etc.] to the string.
+    case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: {
+      FunctionTemplateDecl *FnTmpl 
+        = cast<FunctionTemplateDecl>((Decl *)Active->Entity);
       Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
-                   diag::note_partial_spec_deduct_instantiation_here)
-        << Context.getTypeDeclType(PartialSpec)
-        << Active->InstantiationRange;
+                   diag::note_explicit_template_arg_substitution_here)
+        << FnTmpl << Active->InstantiationRange;
       break;
     }
+        
+    case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
+      if (ClassTemplatePartialSpecializationDecl *PartialSpec
+            = dyn_cast<ClassTemplatePartialSpecializationDecl>(
+                                                    (Decl *)Active->Entity)) {
+        Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+                     diag::note_partial_spec_deduct_instantiation_here)
+          << Context.getTypeDeclType(PartialSpec)
+          << Active->InstantiationRange;
+      } else {
+        FunctionTemplateDecl *FnTmpl
+          = cast<FunctionTemplateDecl>((Decl *)Active->Entity);
+        Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+                     diag::note_function_template_deduction_instantiation_here)
+          << FnTmpl << Active->InstantiationRange;
+      }
+      break;
 
     }
   }
@@ -219,19 +257,20 @@
        ++Active) {
 
     switch(Active->Kind) {
-    case ActiveTemplateInstantiation::PartialSpecDeductionInstantiation:
-      // We're in a template argument deduction context, so SFINAE
-      // applies.
-      return true;
-
+    case ActiveTemplateInstantiation::TemplateInstantiation:
+      // This is a template instantiation, so there is no SFINAE.
+      return false;
+        
     case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
       // A default template argument instantiation may or may not be a
       // SFINAE context; look further up the stack.
       break;
-
-    case ActiveTemplateInstantiation::TemplateInstantiation:
-      // This is a template instantiation, so there is no SFINAE.
-      return false;
+        
+    case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution:
+    case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
+      // We're either substitution explicitly-specified template arguments
+      // or deduced template arguments, so SFINAE applies.
+      return true;
     }
   }
 
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 769e0d2..f597199 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -628,6 +628,28 @@
                                                     FunctionDecl *Tmpl) {
   if (Tmpl->isDeleted())
     New->setDeleted();
+  
+  // If we are performing substituting explicitly-specified template arguments
+  // or deduced template arguments into a function template and we reach this
+  // point, we are now past the point where SFINAE applies and have committed
+  // to keeping the new function template specialization. We therefore 
+  // convert the active template instantiation for the function template 
+  // into a template instantiation for this specific function template
+  // specialization, which is not a SFINAE context, so that we diagnose any
+  // further errors in the declaration itself.
+  typedef Sema::ActiveTemplateInstantiation ActiveInstType;
+  ActiveInstType &ActiveInst = SemaRef.ActiveTemplateInstantiations.back();
+  if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution ||
+      ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) {
+    if (FunctionTemplateDecl *FunTmpl 
+          = dyn_cast<FunctionTemplateDecl>((Decl *)ActiveInst.Entity)) {
+      assert(FunTmpl->getTemplatedDecl() == Tmpl && 
+             "Deduction from the wrong function template?");
+      ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
+      ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
+    }
+  }
+    
   return false;
 }