]> granicus.if.org Git - clang/commitdiff
Keep track of more information within the template instantiation stack, e.g.,
authorDouglas Gregor <dgregor@apple.com>
Wed, 1 Jul 2009 22:01:06 +0000 (22:01 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 1 Jul 2009 22:01:06 +0000 (22:01 +0000)
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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp [new file with mode: 0644]
test/SemaTemplate/operator-template.cpp

index 5847945a4f8e1683b748950ee9acf02866d9de24..af8999e305ea68076cb31f061d5ddc08b82191c0 100644 (file)
@@ -839,6 +839,12 @@ def note_function_template_spec_here : Note<
   
 def note_default_arg_instantiation_here : Note<
   "in instantiation of default argument for '%0' required here">;
+def note_explicit_template_arg_substitution_here : Note<
+  "while substituting explicitly-specified template arguments into function "
+  "template %f, here">;
+def note_function_template_deduction_instantiation_here : Note<
+  "while substituting deduced template arguments into function template %0, "
+  "here">;
 def note_partial_spec_deduct_instantiation_here : Note<
   "during template argument deduction for class template partial "
   "specialization %0, here">;
index 338221e4d4118c253585ab826769503d8965f392..a6c34e88857d24298af50a0c6982e854c8f10f15 100644 (file)
@@ -2359,7 +2359,7 @@ public:
   /// \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 @@ public:
       /// 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 @@ public:
         return true;
 
       case DefaultTemplateArgumentInstantiation:
-      case PartialSpecDeductionInstantiation:
+      case ExplicitTemplateArgumentSubstitution:
+      case DeducedTemplateArgumentSubstitution:
         return X.TemplateArgs == Y.TemplateArgs;
       }
 
@@ -2468,6 +2472,15 @@ public:
                           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.
index ae0e7040654aec2663ddd8915b383c12ba2a1eb4..5a0578f6bcb70f7c5ef740019a5fb2851033b651 100644 (file)
@@ -939,7 +939,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
     // 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 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
   // 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; 
                                   
index 3bc1cf9504b8ccbc3f5f0f8915fe66e247303155..6c2dc77b4cce0045297b2f097b0bb75bc4bb8cfb 100644 (file)
@@ -98,6 +98,30 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
   }
 }
 
+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,
@@ -111,7 +135,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
   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 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
 /// \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 @@ void Sema::PrintInstantiationStack() {
       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 @@ void Sema::PrintInstantiationStack() {
       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 @@ bool Sema::isSFINAEContext() const {
        ++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;
     }
   }
 
index 769e0d222ae907bace029a63e7e4f1f626c28254..f59719992066606b8ee0e416f779712e6e4fc317 100644 (file)
@@ -628,6 +628,28 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
                                                     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;
 }
 
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp
new file mode 100644 (file)
index 0000000..b9057b9
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: clang-cc
+
+typedef char one_byte;
+struct two_bytes { char data[2]; };
+
+template<typename T> one_byte __is_class_check(int T::*);
+template<typename T> two_bytes __is_class_check(...);
+
+template<typename T> struct is_class {
+  static const bool value = sizeof(__is_class_check<T>(0)) == 1;
+};
+
+struct X { };
+
+int array0[is_class<X>::value? 1 : -1];
+int array1[is_class<int>::value? -1 : 1];
+int array2[is_class<char[3]>::value? -1 : 1];
index d65a2781c87f8dfea3139e71e1567cae4cb08823..7039e0ec83de4072794eef9b241b55f3da342449 100644 (file)
@@ -7,10 +7,10 @@ int a(A<int> x) { return operator==(x,1); }
 
 int a0(A<int> x) { return x == 1; }
 
-// FIXME: The diagnostic here is a bit messed up
+// FIXME: the location information for the note isn't very good
 template<class X>struct B{typedef X Y;};
 template<class X>bool operator==(B<X>*,typename B<X>::Y); // \
 expected-error{{overloaded 'operator==' must have at least one parameter of class or enumeration type}} \
-expected-note{{in instantiation of default argument for 'operator==<int>' required here}}
+expected-note{{in instantiation of member function}}
 int a(B<int> x) { return operator==(&x,1); }