Implement support for a pack expansion into a fixed-length
template. Such pack expansions can easily fail at template
instantiation time, if the expanded parameter packs are of the wrong
length. Fixes <rdar://problem/10040867>, PR9021, and the example that
came up today at Going Native.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149685 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 322e473..7cd604d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1887,7 +1887,6 @@
   }
 }
 
-
 QualType Sema::CheckTemplateIdType(TemplateName Name,
                                    SourceLocation TemplateLoc,
                                    TemplateArgumentListInfo &TemplateArgs) {
@@ -1923,9 +1922,6 @@
                                 false, Converted))
     return QualType();
 
-  assert((Converted.size() == Template->getTemplateParameters()->size()) &&
-         "Converted template argument list is too short!");
-
   QualType CanonType;
 
   bool InstantiationDependent = false;
@@ -2866,6 +2862,29 @@
   return false;
 }
 
+/// \brief Diagnose an arity mismatch in the 
+static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
+                                  SourceLocation TemplateLoc,
+                                  TemplateArgumentListInfo &TemplateArgs) {
+  TemplateParameterList *Params = Template->getTemplateParameters();
+  unsigned NumParams = Params->size();
+  unsigned NumArgs = TemplateArgs.size();
+
+  SourceRange Range;
+  if (NumArgs > NumParams)
+    Range = SourceRange(TemplateArgs[NumParams].getLocation(), 
+                        TemplateArgs.getRAngleLoc());
+  S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+    << (NumArgs > NumParams)
+    << (isa<ClassTemplateDecl>(Template)? 0 :
+        isa<FunctionTemplateDecl>(Template)? 1 :
+        isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+    << Template << Range;
+  S.Diag(Template->getLocation(), diag::note_template_decl_here)
+    << Params->getSourceRange();
+  return true;
+}
+
 /// \brief Check that the given template argument list is well-formed
 /// for specializing the given template.
 bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
@@ -2883,26 +2902,6 @@
   bool HasParameterPack =
     NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
 
-  if ((NumArgs > NumParams && !HasParameterPack) ||
-      (NumArgs < Params->getMinRequiredArguments() &&
-       !PartialTemplateArgs)) {
-    // FIXME: point at either the first arg beyond what we can handle,
-    // or the '>', depending on whether we have too many or too few
-    // arguments.
-    SourceRange Range;
-    if (NumArgs > NumParams)
-      Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc);
-    Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
-      << (NumArgs > NumParams)
-      << (isa<ClassTemplateDecl>(Template)? 0 :
-          isa<FunctionTemplateDecl>(Template)? 1 :
-          isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
-      << Template << Range;
-    Diag(Template->getLocation(), diag::note_template_decl_here)
-      << Params->getSourceRange();
-    Invalid = true;
-  }
-
   // C++ [temp.arg]p1:
   //   [...] The type and form of each template-argument specified in
   //   a template-id shall match the type and form specified for the
@@ -2914,10 +2913,12 @@
                                ParamEnd = Params->end();
   unsigned ArgIdx = 0;
   LocalInstantiationScope InstScope(*this, true);
+  bool SawPackExpansion = false;
   while (Param != ParamEnd) {
     if (ArgIdx < NumArgs) {
       // If we have an expanded parameter pack, make sure we don't have too
       // many arguments.
+      // FIXME: This really should fall out from the normal arity checking.
       if (NonTypeTemplateParmDecl *NTTP
                                 = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
         if (NTTP->isExpandedParameterPack() &&
@@ -2951,6 +2952,15 @@
         // Move to the next template parameter.
         ++Param;
       }
+      
+      // If this template argument is a pack expansion, record that fact
+      // and break out; we can't actually check any more.
+      if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) {
+        SawPackExpansion = true;
+        ++ArgIdx;
+        break;
+      }
+      
       ++ArgIdx;
       continue;
     }
@@ -2970,7 +2980,7 @@
     if ((*Param)->isTemplateParameterPack())
       break;
     
-    // We have a default template argument that we will use.
+    // Check whether we have a default argument.
     TemplateArgumentLoc Arg;
 
     // Retrieve the default template argument from the template
@@ -2979,10 +2989,9 @@
     // (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 && "Missing default argument");
-        break;
-      }
+      if (!TTP->hasDefaultArgument())
+        return diagnoseArityMismatch(*this, Template, TemplateLoc, 
+                                     TemplateArgs);
 
       TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this,
                                                              Template,
@@ -2997,10 +3006,9 @@
                                 ArgType);
     } else if (NonTypeTemplateParmDecl *NTTP
                  = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
-      if (!NTTP->hasDefaultArgument()) {
-        assert(Invalid && "Missing default argument");
-        break;
-      }
+      if (!NTTP->hasDefaultArgument())
+        return diagnoseArityMismatch(*this, Template, TemplateLoc, 
+                                     TemplateArgs);
 
       ExprResult E = SubstDefaultTemplateArgument(*this, Template,
                                                               TemplateLoc,
@@ -3016,10 +3024,9 @@
       TemplateTemplateParmDecl *TempParm
         = cast<TemplateTemplateParmDecl>(*Param);
 
-      if (!TempParm->hasDefaultArgument()) {
-        assert(Invalid && "Missing default argument");
-        break;
-      }
+      if (!TempParm->hasDefaultArgument())
+        return diagnoseArityMismatch(*this, Template, TemplateLoc, 
+                                     TemplateArgs);
 
       NestedNameSpecifierLoc QualifierLoc;
       TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
@@ -3057,11 +3064,65 @@
     ++ArgIdx;
   }
 
+  // If we saw a pack expansion, then directly convert the remaining arguments,
+  // because we don't know what parameters they'll match up with.
+  if (SawPackExpansion) {
+    bool AddToArgumentPack
+      = Param != ParamEnd && (*Param)->isTemplateParameterPack();
+    while (ArgIdx < NumArgs) {
+      if (AddToArgumentPack)
+        ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
+      else
+        Converted.push_back(TemplateArgs[ArgIdx].getArgument());
+      ++ArgIdx;
+    }
+
+    // Push the argument pack onto the list of converted arguments.
+    if (AddToArgumentPack) {
+      if (ArgumentPack.empty())
+        Converted.push_back(TemplateArgument(0, 0));
+      else {
+        Converted.push_back(
+          TemplateArgument::CreatePackCopy(Context,
+                                           ArgumentPack.data(),
+                                           ArgumentPack.size()));
+        ArgumentPack.clear();
+      }      
+    }
+
+    return Invalid;
+  }
+
+  // If we have any leftover arguments, then there were too many arguments.
+  // Complain and fail.
+  if (ArgIdx < NumArgs)
+    return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
+  
+  // If we have an expanded parameter pack, make sure we don't have too
+  // many arguments.
+  // FIXME: This really should fall out from the normal arity checking.
+  if (Param != ParamEnd) {
+    if (NonTypeTemplateParmDecl *NTTP
+          = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+      if (NTTP->isExpandedParameterPack() &&
+          ArgumentPack.size() < NTTP->getNumExpansionTypes()) {
+        Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+          << false
+          << (isa<ClassTemplateDecl>(Template)? 0 :
+              isa<FunctionTemplateDecl>(Template)? 1 :
+              isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+          << Template;
+        Diag(Template->getLocation(), diag::note_template_decl_here)
+          << Params->getSourceRange();
+        return true;
+      }
+    }
+  }
+  
   // Form argument packs for each of the parameter packs remaining.
   while (Param != ParamEnd) {
     // If we're checking a partial list of template arguments, don't fill
     // in arguments for non-template parameter packs.
-
     if ((*Param)->isTemplateParameterPack()) {
       if (!HasParameterPack)
         return true;
@@ -3073,7 +3134,8 @@
                                                          ArgumentPack.size()));
         ArgumentPack.clear();
       }
-    }
+    } else if (!PartialTemplateArgs)
+      return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
 
     ++Param;
   }
@@ -4961,9 +5023,6 @@
                                 TemplateArgs, false, Converted))
     return true;
 
-  assert((Converted.size() == ClassTemplate->getTemplateParameters()->size()) &&
-         "Converted template argument list is too short!");
-
   // Find the class template (partial) specialization declaration that
   // corresponds to these arguments.
   if (isPartialSpecialization) {
@@ -5955,9 +6014,6 @@
                                 TemplateArgs, false, Converted))
     return true;
 
-  assert((Converted.size() == ClassTemplate->getTemplateParameters()->size()) &&
-         "Converted template argument list is too short!");
-
   // Find the class template specialization declaration that
   // corresponds to these arguments.
   void *InsertPos = 0;