]> granicus.if.org Git - clang/commitdiff
Improve diagnostics when a default template argument does not match
authorDouglas Gregor <dgregor@apple.com>
Wed, 11 Nov 2009 21:54:23 +0000 (21:54 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 11 Nov 2009 21:54:23 +0000 (21:54 +0000)
with its corresponding template parameter. This can happen when we
performed some substitution into the default template argument and
what we had doesn't match any more, e.g.,

  template<int> struct A;
  template<typename T, template<T> class X = A> class B;

  B<long> b;

Previously, we'd emit a pretty but disembodied diagnostic showing how
the default argument didn't match the template parameter. The
diagnostic was good, but nothing tied it to the *use* of the default
argument in "B<long>". This commit fixes that.

Also, tweak the counting of active template instantiations to avoid
counting non-instantiation records, such as those we create for
(surprise!) checking default arguments, instantiating default
arguments, and performing substitutions as part of template argument
deduction.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86884 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.param/p12.cpp
test/SemaTemplate/default-arguments.cpp

index e0ac0ada8bd837f5d8e9321fb7cc44cd6d1e0918..f0e1be82a7212ea1ef915c0a74c453e8864d0c1d 100644 (file)
@@ -1102,6 +1102,8 @@ def note_partial_spec_deduct_instantiation_here : Note<
 def note_prior_template_arg_substitution : Note<
   "while substituting prior template arguments into %select{non-type|template}0"
   " template parameter%1 %2">;
+def note_template_default_arg_checking : Note<
+  "while checking a default template argument used here">;
   
 def err_field_instantiates_to_function : Error<
   "data member instantiated with function type %0">;
index 38063ac01858e39ad8d28646f4be8a0f8fc77039..5c92b65f82ce7c9e594adc8b701b938b7ea73642 100644 (file)
@@ -355,8 +355,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
     IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
     GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
     CompleteTranslationUnit(CompleteTranslationUnit),
-    NumSFINAEErrors(0), CurrentInstantiationScope(0) {
-
+    NumSFINAEErrors(0), NonInstantiationEntries(0), 
+    CurrentInstantiationScope(0) 
+{
   TUScope = 0;
   if (getLangOptions().CPlusPlus)
     FieldCollector.reset(new CXXFieldCollector());
index b9cacafc4ca6dffc580dd1f1cdd93e2837a84e49..2fea5539a81d77c379207d9fc88eca67c4526d44 100644 (file)
@@ -2889,7 +2889,11 @@ public:
       /// We are substituting prior template arguments into a new
       /// template parameter. The template parameter itself is either a
       /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl.
-      PriorTemplateArgumentSubstitution
+      PriorTemplateArgumentSubstitution,
+      
+      /// We are checking the validity of a default template argument that
+      /// has been used when naming a template-id.
+      DefaultTemplateArgumentChecking
     } Kind;
 
     /// \brief The point of instantiation within the source code.
@@ -2918,6 +2922,10 @@ public:
       : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), 
         NumTemplateArgs(0) {}
 
+    /// \brief Determines whether this template is an actual instantiation
+    /// that should be counted toward the maximum instantiation depth.
+    bool isInstantiationRecord() const;
+    
     friend bool operator==(const ActiveTemplateInstantiation &X,
                            const ActiveTemplateInstantiation &Y) {
       if (X.Kind != Y.Kind)
@@ -2931,6 +2939,7 @@ public:
         return true;
 
       case PriorTemplateArgumentSubstitution:
+      case DefaultTemplateArgumentChecking:
         if (X.Template != Y.Template)
           return false;
           
@@ -2962,6 +2971,11 @@ public:
   llvm::SmallVector<ActiveTemplateInstantiation, 16>
     ActiveTemplateInstantiations;
 
+  /// \brief The number of ActiveTemplateInstantiation entries in
+  /// \c ActiveTemplateInstantiations that are not actual instantiations and,
+  /// therefore, should not be counted as part of the instantiation depth.
+  unsigned NonInstantiationEntries;
+  
   /// \brief The last template from which a template instantiation
   /// error or warning was produced.
   ///
@@ -3037,6 +3051,16 @@ public:
                           unsigned NumTemplateArgs,
                           SourceRange InstantiationRange);
     
+    /// \brief Note that we are checking the default template argument
+    /// against the template parameter for a given template-id.
+    InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+                          TemplateDecl *Template,
+                          NamedDecl *Param,
+                          const TemplateArgument *TemplateArgs,
+                          unsigned NumTemplateArgs,
+                          SourceRange InstantiationRange);
+    
+    
     /// \brief Note that we have finished instantiating this template.
     void Clear();
 
index aace9834416e179ebd69c6af2c4f47f27f251e2f..ee928bccaf9c726d001fd26b6d925c578b2d3079 100644 (file)
@@ -1856,73 +1856,87 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
       continue;
     }
     
-    // Decode the template argument
+    if (ArgIdx < NumArgs) {
+      // Check the template argument we were given.
+      if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, 
+                                TemplateLoc, RAngleLoc, Converted))
+        return true;
+      
+      continue;
+    }
+    
+    // We have a default template argument that we will use.
     TemplateArgumentLoc Arg;
+    
+    // Retrieve the default template argument from the template
+    // parameter. For each kind of template parameter, we substitute the
+    // template arguments provided thus far and any "outer" template arguments
+    // (when the template parameter was part of a nested template) into 
+    // the default argument.
+    if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+      if (!TTP->hasDefaultArgument()) {
+        assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+        break;
+      }
 
-    if (ArgIdx >= NumArgs) {
-      // Retrieve the default template argument from the template
-      // parameter.
-      if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
-        if (TTP->isParameterPack()) {
-          // We have an empty argument pack.
-          Converted.BeginPack();
-          Converted.EndPack();
-          break;
-        }
-
-        if (!TTP->hasDefaultArgument())
-          break;
-
-        DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this, 
-                                                               Template,
-                                                               TemplateLoc,
-                                                               RAngleLoc,
-                                                               TTP,
-                                                               Converted);
-        if (!ArgType)
-          return true;
-                                                               
-        Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()),
-                                  ArgType);
-      } else if (NonTypeTemplateParmDecl *NTTP
-                   = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
-        if (!NTTP->hasDefaultArgument())
-          break;
-
-        Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template,
-                                                                TemplateLoc, 
-                                                                RAngleLoc, 
-                                                                NTTP, 
-                                                                Converted);
-        if (E.isInvalid())
-          return true;
+      DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this, 
+                                                             Template,
+                                                             TemplateLoc,
+                                                             RAngleLoc,
+                                                             TTP,
+                                                             Converted);
+      if (!ArgType)
+        return true;
+                                                             
+      Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()),
+                                ArgType);
+    } else if (NonTypeTemplateParmDecl *NTTP
+                 = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+      if (!NTTP->hasDefaultArgument()) {
+        assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+        break;
+      }
 
-        Expr *Ex = E.takeAs<Expr>();
-        Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex);
-      } else {
-        TemplateTemplateParmDecl *TempParm
-          = cast<TemplateTemplateParmDecl>(*Param);
+      Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template,
+                                                              TemplateLoc, 
+                                                              RAngleLoc, 
+                                                              NTTP, 
+                                                              Converted);
+      if (E.isInvalid())
+        return true;
 
-        if (!TempParm->hasDefaultArgument())
-          break;
+      Expr *Ex = E.takeAs<Expr>();
+      Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex);
+    } else {
+      TemplateTemplateParmDecl *TempParm
+        = cast<TemplateTemplateParmDecl>(*Param);
 
-        TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
-                                                         TemplateLoc, 
-                                                         RAngleLoc, 
-                                                         TempParm,
-                                                         Converted);
-        if (Name.isNull())
-          return true;
-        
-        Arg = TemplateArgumentLoc(TemplateArgument(Name), 
-                    TempParm->getDefaultArgument().getTemplateQualifierRange(),
-                    TempParm->getDefaultArgument().getTemplateNameLoc());
+      if (!TempParm->hasDefaultArgument()) {
+        assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+        break;
       }
-    } else {
-      // Retrieve the template argument produced by the user.
-      Arg = TemplateArgs[ArgIdx];
+
+      TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
+                                                       TemplateLoc, 
+                                                       RAngleLoc, 
+                                                       TempParm,
+                                                       Converted);
+      if (Name.isNull())
+        return true;
+      
+      Arg = TemplateArgumentLoc(TemplateArgument(Name), 
+                  TempParm->getDefaultArgument().getTemplateQualifierRange(),
+                  TempParm->getDefaultArgument().getTemplateNameLoc());
     }
     
+    // Introduce an instantiation record that describes where we are using
+    // the default template argument.
+    InstantiatingTemplate Instantiating(*this, RAngleLoc, Template, *Param,
+                                        Converted.getFlatArguments(),
+                                        Converted.flatSize(),
+                                        SourceRange(TemplateLoc, RAngleLoc));    
+    
+    // Check the default template argument.
     if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc,
                               RAngleLoc, Converted))
       return true;
index b1e0481932ffeca231da1112dddd17b39721dd91..b303dce06ff62e910d6182de1e1856d8d069ca58 100644 (file)
@@ -96,6 +96,23 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
   return Result;
 }
 
+bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
+  switch (Kind) {
+  case TemplateInstantiation:
+  case DefaultTemplateArgumentInstantiation:
+  case DefaultFunctionArgumentInstantiation:
+    return true;
+      
+  case ExplicitTemplateArgumentSubstitution:
+  case DeducedTemplateArgumentSubstitution:
+  case PriorTemplateArgumentSubstitution:
+  case DefaultTemplateArgumentChecking:
+    return false;
+  }
+  
+  return true;
+}
+
 Sema::InstantiatingTemplate::
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
                       Decl *Entity,
@@ -113,7 +130,6 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
     Inst.NumTemplateArgs = 0;
     Inst.InstantiationRange = InstantiationRange;
     SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-    Invalid = false;
   }
 }
 
@@ -137,7 +153,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
     Inst.NumTemplateArgs = NumTemplateArgs;
     Inst.InstantiationRange = InstantiationRange;
     SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-    Invalid = false;
   }
 }
 
@@ -161,7 +176,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
     Inst.NumTemplateArgs = NumTemplateArgs;
     Inst.InstantiationRange = InstantiationRange;
     SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-    Invalid = false;
+    
+    if (!Inst.isInstantiationRecord())
+      ++SemaRef.NonInstantiationEntries;
   }
 }
 
@@ -173,20 +190,19 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
                                          SourceRange InstantiationRange)
   : SemaRef(SemaRef) {
 
-  Invalid = CheckInstantiationDepth(PointOfInstantiation,
-                                    InstantiationRange);
-  if (!Invalid) {
-    ActiveTemplateInstantiation Inst;
-    Inst.Kind
-      = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
-    Inst.PointOfInstantiation = PointOfInstantiation;
-    Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
-    Inst.TemplateArgs = TemplateArgs;
-    Inst.NumTemplateArgs = NumTemplateArgs;
-    Inst.InstantiationRange = InstantiationRange;
-    SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-    Invalid = false;
-  }
+  Invalid = false;
+    
+  ActiveTemplateInstantiation Inst;
+  Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
+  Inst.PointOfInstantiation = PointOfInstantiation;
+  Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
+  Inst.TemplateArgs = TemplateArgs;
+  Inst.NumTemplateArgs = NumTemplateArgs;
+  Inst.InstantiationRange = InstantiationRange;
+  SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+      
+  assert(!Inst.isInstantiationRecord());
+  ++SemaRef.NonInstantiationEntries;
 }
 
 Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
@@ -219,19 +235,20 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
                       const TemplateArgument *TemplateArgs,
                       unsigned NumTemplateArgs,
                       SourceRange InstantiationRange) : SemaRef(SemaRef) {
-  Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+  Invalid = false;
   
-  if (!Invalid) {
-    ActiveTemplateInstantiation Inst;
-    Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
-    Inst.PointOfInstantiation = PointOfInstantiation;
-    Inst.Template = Template;
-    Inst.Entity = reinterpret_cast<uintptr_t>(Param);
-    Inst.TemplateArgs = TemplateArgs;
-    Inst.NumTemplateArgs = NumTemplateArgs;
-    Inst.InstantiationRange = InstantiationRange;
-    SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-  }
+  ActiveTemplateInstantiation Inst;
+  Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+  Inst.PointOfInstantiation = PointOfInstantiation;
+  Inst.Template = Template;
+  Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+  Inst.TemplateArgs = TemplateArgs;
+  Inst.NumTemplateArgs = NumTemplateArgs;
+  Inst.InstantiationRange = InstantiationRange;
+  SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+  
+  assert(!Inst.isInstantiationRecord());
+  ++SemaRef.NonInstantiationEntries;
 }
 
 Sema::InstantiatingTemplate::
@@ -241,23 +258,51 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
                       const TemplateArgument *TemplateArgs,
                       unsigned NumTemplateArgs,
                       SourceRange InstantiationRange) : SemaRef(SemaRef) {
-  Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+  Invalid = false;
+  ActiveTemplateInstantiation Inst;
+  Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+  Inst.PointOfInstantiation = PointOfInstantiation;
+  Inst.Template = Template;
+  Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+  Inst.TemplateArgs = TemplateArgs;
+  Inst.NumTemplateArgs = NumTemplateArgs;
+  Inst.InstantiationRange = InstantiationRange;
+  SemaRef.ActiveTemplateInstantiations.push_back(Inst);
   
-  if (!Invalid) {
-    ActiveTemplateInstantiation Inst;
-    Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
-    Inst.PointOfInstantiation = PointOfInstantiation;
-    Inst.Template = Template;
-    Inst.Entity = reinterpret_cast<uintptr_t>(Param);
-    Inst.TemplateArgs = TemplateArgs;
-    Inst.NumTemplateArgs = NumTemplateArgs;
-    Inst.InstantiationRange = InstantiationRange;
-    SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-  }
+  assert(!Inst.isInstantiationRecord());
+  ++SemaRef.NonInstantiationEntries;
+}
+
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+                      TemplateDecl *Template,
+                      NamedDecl *Param,
+                      const TemplateArgument *TemplateArgs,
+                      unsigned NumTemplateArgs,
+                      SourceRange InstantiationRange) : SemaRef(SemaRef) {
+  Invalid = false;
+  
+  ActiveTemplateInstantiation Inst;
+  Inst.Kind = ActiveTemplateInstantiation::DefaultTemplateArgumentChecking;
+  Inst.PointOfInstantiation = PointOfInstantiation;
+  Inst.Template = Template;
+  Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+  Inst.TemplateArgs = TemplateArgs;
+  Inst.NumTemplateArgs = NumTemplateArgs;
+  Inst.InstantiationRange = InstantiationRange;
+  SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+  
+  assert(!Inst.isInstantiationRecord());
+  ++SemaRef.NonInstantiationEntries;
 }
 
 void Sema::InstantiatingTemplate::Clear() {
   if (!Invalid) {
+    if (!SemaRef.ActiveTemplateInstantiations.back().isInstantiationRecord()) {
+      assert(SemaRef.NonInstantiationEntries > 0);
+      --SemaRef.NonInstantiationEntries;
+    }
+    
     SemaRef.ActiveTemplateInstantiations.pop_back();
     Invalid = true;
   }
@@ -266,8 +311,11 @@ void Sema::InstantiatingTemplate::Clear() {
 bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
                                         SourceLocation PointOfInstantiation,
                                            SourceRange InstantiationRange) {
-  if (SemaRef.ActiveTemplateInstantiations.size()
-       <= SemaRef.getLangOptions().InstantiationDepth)
+  assert(SemaRef.NonInstantiationEntries <=
+                                   SemaRef.ActiveTemplateInstantiations.size());
+  if ((SemaRef.ActiveTemplateInstantiations.size() - 
+          SemaRef.NonInstantiationEntries)
+        <= SemaRef.getLangOptions().InstantiationDepth)
     return false;
 
   SemaRef.Diag(PointOfInstantiation,
@@ -391,6 +439,17 @@ void Sema::PrintInstantiationStack() {
         << Active->InstantiationRange;
       break;
     }
+
+    case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: {
+      Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+                   diag::note_template_default_arg_checking)
+        << getTemplateArgumentBindingsText(
+                                     Active->Template->getTemplateParameters(), 
+                                           Active->TemplateArgs, 
+                                           Active->NumTemplateArgs)
+        << Active->InstantiationRange;
+      break;
+    }
     }
   }
 }
@@ -401,17 +460,17 @@ bool Sema::isSFINAEContext() const {
          Active = ActiveTemplateInstantiations.rbegin(),
          ActiveEnd = ActiveTemplateInstantiations.rend();
        Active != ActiveEnd;
-       ++Active) {
-
+       ++Active) 
+  {
     switch(Active->Kind) {
     case ActiveTemplateInstantiation::TemplateInstantiation:
     case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
-
       // This is a template instantiation, so there is no SFINAE.
       return false;
 
     case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
     case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution:
+    case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking:
       // A default template argument instantiation and substitution into
       // template parameters with arguments for prior parameters may or may 
       // not be a SFINAE context; look further up the stack.
index ab712946dc599bdbd5059efd5ba0b8e6545f742e..47d2701bcd3613440ed5ac429a5148f0c50a2cf6 100644 (file)
@@ -1285,6 +1285,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
       (void) FunTmpl;
       ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
       ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
+      --SemaRef.NonInstantiationEntries;
     }
   }
 
index 10bdb6566491174bd9a9b6bac46fc47fe4f7c0e9..3864fbeaa11e99c2e7e1f39e5bc9c867a8c94ed2 100644 (file)
@@ -36,4 +36,4 @@ template<template<class, int> class // expected-note{{previous template template
            = Y1> // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
   class C1 {};
 
-C1<> c1;
+C1<> c1; // expected-note{{while checking a default template argument}}
index e1999218dd0a251b01d932bde51940b28311e999..e082693aa52ebb78dc63fa877c5627bf3da66728 100644 (file)
@@ -116,5 +116,5 @@ template<typename T,
   struct X6 {};
 
 X6<int> x6a;
-X6<long> x6b;
+X6<long> x6b; // expected-note{{while checking a default template argument}}
 X6<long, X5b> x6c;