re PR c++/31431 (ICE with invalid parameter pack)
authorDouglas Gregor <doug.gregor@gmail.com>
Fri, 25 May 2007 13:15:04 +0000 (13:15 +0000)
committerDoug Gregor <dgregor@gcc.gnu.org>
Fri, 25 May 2007 13:15:04 +0000 (13:15 +0000)
2007-05-25  Douglas Gregor <doug.gregor@gmail.com>

PR c++/31431
PR c++/31432
PR c++/31434
PR c++/31435
PR c++/31437
PR c++/31438
PR c++/31442
PR c++/31443
PR c++/31444
PR c++/31445
* error.c (dump_type): Dump TYPE_ARGUMENT_PACK nodes.
* cp-tree.h (check_for_bare_parameter_packs): Returns bool.
* pt.c (check_for_bare_parameter_packs): Return bool indicated
whether everything was okay. Fix indentation.
(push_template_decl_real): Check for bare parameter packs in
function parameters; where errors occur, mark the parameter types
with ERROR_MARK_NODEs to avert ICEs.
(coerce_template_parameter_pack): New.
(coerce_template_parms): Moved parameter pack coercion into
coerce_template_parameter_pack, and permit it anywhere in the
template parameter list (not just at the end). Parameter and
argument indices can vary (somewhat) separately now, so add
PARM_IDX and ARG_IDX.
(fn_type_unification): Don't set an argument pack as incomplete if
no argument pack was deduced.
(type_unification_real): If a type parameter is a parameter pack
and has not otherwise been deduced, it will be deduced to an empty
parameter pack.
(more_specialized_fn): Use the actual lengths of the argument
lists when comparing against expansions.
* semantics.c (finish_member_declaration): If a field's type has
bare parameter packs, error and set its type to ERROR_MARK_NODE.

2007-05-25  Douglas Gregor <doug.gregor@gmail.com>

PR c++/31431
PR c++/31432
PR c++/31434
PR c++/31435
PR c++/31437
PR c++/31438
PR c++/31442
PR c++/31443
PR c++/31444
PR c++/31445
* g++.dg/cpp0x/pr31431.C: New.
* g++.dg/cpp0x/pr31437.C: New.
* g++.dg/cpp0x/pr31442.C: New.
* g++.dg/cpp0x/pr31444.C: New.
* g++.dg/cpp0x/pr31431-2.C: New.
* g++.dg/cpp0x/pr31432.C: New.
* g++.dg/cpp0x/pr31434.C: New.
* g++.dg/cpp0x/pr31438.C: New.
* g++.dg/cpp0x/pr31443.C: New.
* g++.dg/cpp0x/pr31445.C: New.
* g++.dg/cpp0x/variadic-crash1.C: New.

From-SVN: r125062

17 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/error.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/pr31431-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr31431.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr31432.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr31434.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr31437.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr31438.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr31442.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr31443.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr31444.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr31445.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/variadic-crash1.C [new file with mode: 0644]

index 7738d1f..f2c6b6a 100644 (file)
@@ -1,3 +1,38 @@
+2007-05-25  Douglas Gregor <doug.gregor@gmail.com>
+
+       PR c++/31431
+       PR c++/31432
+       PR c++/31434
+       PR c++/31435
+       PR c++/31437
+       PR c++/31438
+       PR c++/31442
+       PR c++/31443
+       PR c++/31444
+       PR c++/31445
+       * error.c (dump_type): Dump TYPE_ARGUMENT_PACK nodes.
+       * cp-tree.h (check_for_bare_parameter_packs): Returns bool.
+       * pt.c (check_for_bare_parameter_packs): Return bool indicated
+       whether everything was okay. Fix indentation.
+       (push_template_decl_real): Check for bare parameter packs in
+       function parameters; where errors occur, mark the parameter types
+       with ERROR_MARK_NODEs to avert ICEs.
+       (coerce_template_parameter_pack): New.
+       (coerce_template_parms): Moved parameter pack coercion into
+       coerce_template_parameter_pack, and permit it anywhere in the
+       template parameter list (not just at the end). Parameter and
+       argument indices can vary (somewhat) separately now, so add
+       PARM_IDX and ARG_IDX.
+       (fn_type_unification): Don't set an argument pack as incomplete if
+       no argument pack was deduced.
+       (type_unification_real): If a type parameter is a parameter pack
+       and has not otherwise been deduced, it will be deduced to an empty
+       parameter pack.
+       (more_specialized_fn): Use the actual lengths of the argument
+       lists when comparing against expansions.
+       * semantics.c (finish_member_declaration): If a field's type has
+       bare parameter packs, error and set its type to ERROR_MARK_NODE.
+
 2007-05-24  Danny Smith  <dannysmith@users.sourceforge.net>
 
        PR target/27067
index df067c9..413b224 100644 (file)
@@ -4393,7 +4393,7 @@ extern bool uses_parameter_packs                (tree);
 extern bool template_parameter_pack_p           (tree);
 extern bool template_parms_variadic_p           (tree);
 extern tree make_pack_expansion                 (tree);
-extern void check_for_bare_parameter_packs      (tree);
+extern bool check_for_bare_parameter_packs      (tree);
 extern int template_class_depth                        (tree);
 extern int is_specialization_of                        (tree, tree);
 extern bool is_specialization_of_friend                (tree, tree);
index 7329109..fcc7b08 100644 (file)
@@ -395,6 +395,19 @@ dump_type (tree t, int flags)
       pp_cxx_identifier (cxx_pp, "...");
       break;
 
+    case TYPE_ARGUMENT_PACK:
+      {
+        tree args = ARGUMENT_PACK_ARGS (t);
+        int i;
+        for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
+          {
+            if (i)
+              pp_separate_with_comma (cxx_pp);
+            dump_type (TREE_VEC_ELT (args, i), flags);
+          }
+      }
+      break;
+
     default:
       pp_unsupported_tree (cxx_pp, t);
       /* Fall through to error.  */
index 05d7752..584e6cf 100644 (file)
@@ -2599,15 +2599,18 @@ make_pack_expansion (tree arg)
    where "args" is a parameter pack. check_for_bare_parameter_packs
    should not be called for the subexpressions args, h(args),
    g(h(args)), or f(g(h(args))), because we would produce erroneous
-   error messages.  */
-void 
+   error messages. 
+
+   Returns TRUE if there were no bare parameter packs, returns FALSE
+   (and emits an error) if there were bare parameter packs.*/
+bool 
 check_for_bare_parameter_packs (tree t)
 {
   tree parameter_packs = NULL_TREE;
   struct find_parameter_pack_data ppd;
 
   if (!processing_template_decl || !t || t == error_mark_node)
-    return;
+    return true;
 
   if (TREE_CODE (t) == TYPE_DECL)
     t = TREE_TYPE (t);
@@ -2617,25 +2620,30 @@ check_for_bare_parameter_packs (tree t)
   walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
   pointer_set_destroy (ppd.visited);
 
-  if (parameter_packs) {
-    error ("parameter packs not expanded with `...':");
-    while (parameter_packs)
-      {
-        tree pack = TREE_VALUE (parameter_packs);
-        tree name = NULL_TREE;
-
-        if (TREE_CODE (pack) == TEMPLATE_TYPE_PARM
-            || TREE_CODE (pack) == TEMPLATE_TEMPLATE_PARM)
-          name = TYPE_NAME (pack);
-       else if (TREE_CODE (pack) == TEMPLATE_PARM_INDEX)
-         name = DECL_NAME (TEMPLATE_PARM_DECL (pack));
-        else
-          name = DECL_NAME (pack);
-        inform ("        %qD", name);
-
-        parameter_packs = TREE_CHAIN (parameter_packs);
-      }
-  }
+  if (parameter_packs) 
+    {
+      error ("parameter packs not expanded with `...':");
+      while (parameter_packs)
+        {
+          tree pack = TREE_VALUE (parameter_packs);
+          tree name = NULL_TREE;
+
+          if (TREE_CODE (pack) == TEMPLATE_TYPE_PARM
+              || TREE_CODE (pack) == TEMPLATE_TEMPLATE_PARM)
+            name = TYPE_NAME (pack);
+          else if (TREE_CODE (pack) == TEMPLATE_PARM_INDEX)
+            name = DECL_NAME (TEMPLATE_PARM_DECL (pack));
+          else
+            name = DECL_NAME (pack);
+          inform ("        %qD", name);
+
+          parameter_packs = TREE_CHAIN (parameter_packs);
+        }
+
+      return false;
+    }
+
+  return true;
 }
 
 /* Expand any parameter packs that occur in the template arguments in
@@ -3376,7 +3384,7 @@ process_partial_specialization (tree decl)
 
   DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)
     = tree_cons (specargs, inner_parms,
-                DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
+                 DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
   TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
   return decl;
 }
@@ -3692,7 +3700,38 @@ push_template_decl_real (tree decl, bool is_friend)
 
   /* Ensure that there are no parameter packs in the type of this
      declaration that have not been expanded.  */
-  check_for_bare_parameter_packs (TREE_TYPE (decl));
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      /* Check each of the arguments individually to see if there are
+         any bare parameter packs.  */
+      tree type = TREE_TYPE (decl);
+      tree arg = DECL_ARGUMENTS (decl);
+      tree argtype = TYPE_ARG_TYPES (type);
+
+      while (arg && argtype)
+        {
+          if (!FUNCTION_PARAMETER_PACK_P (arg)
+              && !check_for_bare_parameter_packs (TREE_TYPE (arg)))
+            {
+            /* This is a PARM_DECL that contains unexpanded parameter
+               packs. We have already complained about this in the
+               check_for_bare_parameter_packs call, so just replace
+               these types with ERROR_MARK_NODE.  */
+              TREE_TYPE (arg) = error_mark_node;
+              TREE_VALUE (argtype) = error_mark_node;
+            }
+
+          arg = TREE_CHAIN (arg);
+          argtype = TREE_CHAIN (argtype);
+        }
+
+      /* Check for bare parameter packs in the return type and the
+         exception specifiers.  */
+      check_for_bare_parameter_packs (TREE_TYPE (type));
+      check_for_bare_parameter_packs (TYPE_RAISES_EXCEPTIONS (type));
+    }
+  else
+    check_for_bare_parameter_packs (TREE_TYPE (decl));
 
   if (is_partial)
     return process_partial_specialization (decl);
@@ -4740,6 +4779,121 @@ convert_template_argument (tree parm,
   return val;
 }
 
+/* Coerces the remaining template arguments in INNER_ARGS (from
+   ARG_IDX to the end) into the parameter pack at PARM_IDX in PARMS.
+   Returns the coerced argument pack. PARM_IDX is the position of this
+   parameter in the template parameter list. ARGS is the original
+   template argument list.  */
+static tree
+coerce_template_parameter_pack (tree parms,
+                                int parm_idx,
+                                tree args,
+                                tree inner_args,
+                                int arg_idx,
+                                tree new_args,
+                                int* lost,
+                                tree in_decl,
+                                tsubst_flags_t complain)
+{
+  tree parm = TREE_VEC_ELT (parms, parm_idx);
+  int nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
+  tree packed_args;
+  tree argument_pack;
+  tree packed_types = NULL_TREE;
+
+  if (arg_idx > nargs)
+    arg_idx = nargs;
+
+  packed_args = make_tree_vec (nargs - arg_idx);
+
+  if (TREE_CODE (TREE_VALUE (parm)) == PARM_DECL
+      && uses_parameter_packs (TREE_TYPE (TREE_VALUE (parm))))
+    {
+      /* When the template parameter is a non-type template
+         parameter pack whose type uses parameter packs, we need
+         to look at each of the template arguments
+         separately. Build a vector of the types for these
+         non-type template parameters in PACKED_TYPES.  */
+      tree expansion 
+        = make_pack_expansion (TREE_TYPE (TREE_VALUE (parm)));
+      packed_types = tsubst_pack_expansion (expansion, args,
+                                            complain, in_decl);
+
+      if (packed_types == error_mark_node)
+        return error_mark_node;
+
+      /* Check that we have the right number of arguments.  */
+      if (arg_idx < nargs
+          && !PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, arg_idx))
+          && nargs - arg_idx != TREE_VEC_LENGTH (packed_types))
+        {
+          int needed_parms 
+            = TREE_VEC_LENGTH (parms) - 1 + TREE_VEC_LENGTH (packed_types);
+          error ("wrong number of template arguments (%d, should be %d)",
+                 nargs, needed_parms);
+          return error_mark_node;
+        }
+
+      /* If we aren't able to check the actual arguments now
+         (because they haven't been expanded yet), we can at least
+         verify that all of the types used for the non-type
+         template parameter pack are, in fact, valid for non-type
+         template parameters.  */
+      if (arg_idx < nargs 
+          && PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, arg_idx)))
+        {
+          int j, len = TREE_VEC_LENGTH (packed_types);
+          for (j = 0; j < len; ++j)
+            {
+              tree t = TREE_VEC_ELT (packed_types, j);
+              if (invalid_nontype_parm_type_p (t, complain))
+                return error_mark_node;
+            }
+        }
+    }
+
+  /* Convert the remaining arguments, which will be a part of the
+     parameter pack "parm".  */
+  for (; arg_idx < nargs; ++arg_idx)
+    {
+      tree arg = TREE_VEC_ELT (inner_args, arg_idx);
+      tree actual_parm = TREE_VALUE (parm);
+
+      if (packed_types && !PACK_EXPANSION_P (arg))
+        {
+          /* When we have a vector of types (corresponding to the
+             non-type template parameter pack that uses parameter
+             packs in its type, as mention above), and the
+             argument is not an expansion (which expands to a
+             currently unknown number of arguments), clone the
+             parm and give it the next type in PACKED_TYPES.  */
+          actual_parm = copy_node (actual_parm);
+          TREE_TYPE (actual_parm) = 
+            TREE_VEC_ELT (packed_types, arg_idx - parm_idx);
+        }
+
+      arg = convert_template_argument (actual_parm, 
+                                       arg, new_args, complain, parm_idx,
+                                       in_decl);
+      if (arg == error_mark_node)
+        (*lost)++;
+      TREE_VEC_ELT (packed_args, arg_idx - parm_idx) = arg; 
+    }
+
+  if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL
+      || TREE_CODE (TREE_VALUE (parm)) == TEMPLATE_DECL)
+    argument_pack = make_node (TYPE_ARGUMENT_PACK);
+  else
+    {
+      argument_pack = make_node (NONTYPE_ARGUMENT_PACK);
+      TREE_TYPE (argument_pack) = TREE_TYPE (TREE_VALUE (parm));
+      TREE_CONSTANT (argument_pack) = 1;
+    }
+
+  SET_ARGUMENT_PACK_ARGS (argument_pack, packed_args);
+  return argument_pack;
+}
+
 /* Convert all template arguments to their appropriate types, and
    return a vector containing the innermost resulting template
    arguments.  If any error occurs, return error_mark_node. Error and
@@ -4760,7 +4914,7 @@ coerce_template_parms (tree parms,
                       bool require_all_args,
                       bool use_default_args)
 {
-  int nparms, nargs, i, lost = 0;
+  int nparms, nargs, parm_idx, arg_idx, lost = 0;
   tree inner_args;
   tree new_args;
   tree new_inner_args;
@@ -4770,7 +4924,7 @@ coerce_template_parms (tree parms,
      variadic template parameter list. Since it's an int, we can also
      subtract it from nparms to get the number of non-variadic
      parameters.  */
-  int variadic_p = template_parms_variadic_p (parms) ? 1 : 0;
+  int variadic_p = 0;
 
   inner_args 
     = expand_template_argument_pack (INNERMOST_TEMPLATE_ARGS (args));
@@ -4778,6 +4932,17 @@ coerce_template_parms (tree parms,
   nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
   nparms = TREE_VEC_LENGTH (parms);
 
+  /* Determine if there are any parameter packs.  */
+  for (parm_idx = 0; parm_idx < nparms; ++parm_idx)
+    {
+      tree tparm = TREE_VALUE (TREE_VEC_ELT (parms, parm_idx));
+      if (template_parameter_pack_p (tparm))
+        {
+          variadic_p = 1;
+          break;
+        }
+    }
+
   if ((nargs > nparms - variadic_p && !variadic_p)
       || (nargs < nparms - variadic_p
          && require_all_args
@@ -4810,164 +4975,88 @@ coerce_template_parms (tree parms,
   skip_evaluation = false;
   new_inner_args = make_tree_vec (nparms);
   new_args = add_outermost_template_args (args, new_inner_args);
-  for (i = 0; i < nparms - variadic_p; i++)
+  for (parm_idx = 0, arg_idx = 0; parm_idx < nparms; parm_idx++, arg_idx++)
     {
       tree arg;
       tree parm;
 
       /* Get the Ith template parameter.  */
-      parm = TREE_VEC_ELT (parms, i);
+      parm = TREE_VEC_ELT (parms, parm_idx);
  
       if (parm == error_mark_node)
       {
-        TREE_VEC_ELT (new_inner_args, i) = error_mark_node;
+        TREE_VEC_ELT (new_inner_args, arg_idx) = error_mark_node;
         continue;
       }
 
-      /* Calculate the Ith argument.  */
-      if (i < nargs)
+      /* Calculate the next argument.  */
+      if (template_parameter_pack_p (TREE_VALUE (parm)))
         {
-          arg = TREE_VEC_ELT (inner_args, i);
-        
-          if (PACK_EXPANSION_P (arg))
+          /* All remaining arguments will be placed in the
+             template parameter pack PARM.  */
+          arg = coerce_template_parameter_pack (parms, parm_idx, args, 
+                                                inner_args, arg_idx,
+                                                new_args, &lost,
+                                                in_decl, complain);
+          
+          /* Store this argument.  */
+          if (arg == error_mark_node)
+            lost++;
+          TREE_VEC_ELT (new_inner_args, parm_idx) = arg;
+
+          /* We are done with all of the arguments.  */
+          arg_idx = nargs;
+
+          continue;
+        }
+      else if (arg_idx < nargs)
+        {
+          arg = TREE_VEC_ELT (inner_args, arg_idx);
+
+          if (arg && PACK_EXPANSION_P (arg))
             {
-              /* If ARG is a pack expansion, then PARM must be
-                 a template parameter pack. We can't expand into a
+              /* If ARG is a pack expansion, but PARM is not a
+                 template parameter pack (if it were, we would have
+                 handled it above), we're trying to expand into a
                  fixed-length argument list.  */
-              tree actual_parm = TREE_VALUE (parm);
-              bool parm_is_parameter_pack 
-               = template_parameter_pack_p (actual_parm);
-
-              if (!parm_is_parameter_pack)
-                {
-                  if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
-                    error ("cannot expand %<%E%> into a fixed-length "
-                           "argument list", arg);
-                  else
-                    error ("cannot expand %<%T%> into a fixed-length "
-                           "argument list", arg);
-                }
+              if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+                error ("cannot expand %<%E%> into a fixed-length "
+                       "argument list", arg);
+              else
+                error ("cannot expand %<%T%> into a fixed-length "
+                       "argument list", arg);
             }
         }
       else if (require_all_args)
-       /* There must be a default arg in this case.  */
-       arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
-                                  complain, in_decl);
+        /* There must be a default arg in this case.  */
+        arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
+                                   complain, in_decl);
       else
        break;
 
-      gcc_assert (arg);
       if (arg == error_mark_node)
        {
          if (complain & tf_error)
-           error ("template argument %d is invalid", i + 1);
-       }
+           error ("template argument %d is invalid", arg_idx + 1);
+       }
+      else if (!arg)
+        /* This only occurs if there was an error in the template
+           parameter list itself (which we would already have
+           reported) that we are trying to recover from, e.g., a class
+           template with a parameter list such as
+           template<typename..., typename>.  */
+        return error_mark_node;
       else
        arg = convert_template_argument (TREE_VALUE (parm),
-                                        arg, new_args, complain, i,
-                                        in_decl);
+                                        arg, new_args, complain, 
+                                         parm_idx, in_decl);
 
       if (arg == error_mark_node)
        lost++;
-      TREE_VEC_ELT (new_inner_args, i) = arg;
+      TREE_VEC_ELT (new_inner_args, arg_idx) = arg;
     }
   skip_evaluation = saved_skip_evaluation;
 
-  if (variadic_p)
-    {
-      int expected_len = nargs - nparms + 1;
-      tree parm = TREE_VEC_ELT (parms, nparms - 1);
-      tree packed_args;
-      tree argument_pack;
-      tree packed_types = NULL_TREE;
-      
-      packed_args = make_tree_vec (expected_len >= 0 ? expected_len : 0);
-
-      if (TREE_CODE (TREE_VALUE (parm)) == PARM_DECL
-         && uses_parameter_packs (TREE_TYPE (TREE_VALUE (parm))))
-       {
-         /* When the template parameter is a non-type template
-            parameter pack whose type uses parameter packs, we need
-            to look at each of the template arguments
-            separately. Build a vector of the types for these
-            non-type template parameters in PACKED_TYPES.  */
-         tree expansion 
-           = make_pack_expansion (TREE_TYPE (TREE_VALUE (parm)));
-         packed_types = tsubst_pack_expansion (expansion, args,
-                                               complain, in_decl);
-
-         if (packed_types == error_mark_node)
-           return error_mark_node;
-
-         /* Check that we have the right number of arguments.  */
-         if (i < nargs
-             && !PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, i))
-             && nargs - i != TREE_VEC_LENGTH (packed_types))
-           {
-             error ("wrong number of template arguments (%d, should be %d)",
-                    nargs, nparms - 1 + TREE_VEC_LENGTH (packed_types));
-             return error_mark_node;
-           }
-
-         /* If we aren't able to check the actual arguments now
-            (because they haven't been expanded yet), we can at least
-            verify that all of the types used for the non-type
-            template parameter pack are, in fact, valid for non-type
-            template parameters.  */
-         if (i < nargs && PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, i)))
-           {
-             int j, len = TREE_VEC_LENGTH (packed_types);
-             for (j = 0; j < len; ++j)
-               {
-                 tree t = TREE_VEC_ELT (packed_types, j);
-                 if (invalid_nontype_parm_type_p (t, complain))
-                   return error_mark_node;
-               }
-           }
-       }
-
-      /* Convert the remaining arguments, which will be a part of the
-         parameter pack "parm".  */
-      for (; i < nargs; ++i)
-        {
-          tree arg = TREE_VEC_ELT (inner_args, i);
-         tree actual_parm = TREE_VALUE (parm);
-
-         if (packed_types && !PACK_EXPANSION_P (arg))
-           {
-             /* When we have a vector of types (corresponding to the
-                non-type template parameter pack that uses parameter
-                packs in its type, as mention above), and the
-                argument is not an expansion (which expands to a
-                currently unknown number of arguments), clone the
-                parm and give it the next type in PACKED_TYPES.  */
-             actual_parm = copy_node (actual_parm);
-             TREE_TYPE (actual_parm) = 
-               TREE_VEC_ELT (packed_types, i - nparms + 1);
-           }
-
-          arg = convert_template_argument (actual_parm, 
-                                           arg, new_args, complain, i,
-                                           in_decl);
-          if (arg == error_mark_node)
-            lost++;
-          TREE_VEC_ELT (packed_args, i - nparms + 1) = arg; 
-        }
-
-      if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL
-          || TREE_CODE (TREE_VALUE (parm)) == TEMPLATE_DECL)
-          argument_pack = make_node (TYPE_ARGUMENT_PACK);
-      else
-        {
-          argument_pack = make_node (NONTYPE_ARGUMENT_PACK);
-          TREE_TYPE (argument_pack) = TREE_TYPE (TREE_VALUE (parm));
-          TREE_CONSTANT (argument_pack) = 1;
-        }
-
-      SET_ARGUMENT_PACK_ARGS (argument_pack, packed_args);
-      TREE_VEC_ELT (new_inner_args, nparms - 1) = argument_pack;
-    }
-
   if (lost)
     return error_mark_node;
 
@@ -11055,8 +11144,12 @@ fn_type_unification (tree fn,
               /* Mark the argument pack as "incomplete". We could
                  still deduce more arguments during unification.  */
               targ = TMPL_ARG (converted_args, level, idx);
-              ARGUMENT_PACK_INCOMPLETE_P(targ) = 1;
-              ARGUMENT_PACK_EXPLICIT_ARGS (targ) = ARGUMENT_PACK_ARGS (targ);
+              if (targ)
+                {
+                  ARGUMENT_PACK_INCOMPLETE_P(targ) = 1;
+                  ARGUMENT_PACK_EXPLICIT_ARGS (targ) 
+                    = ARGUMENT_PACK_ARGS (targ);
+                }
 
               /* We have some incomplete argument packs.  */
               incomplete_argument_packs_p = true;
@@ -11425,6 +11518,27 @@ type_unification_real (tree tparms,
                 }
             }
 
+          /* If the type parameter is a parameter pack, then it will
+             be deduced to an empty parameter pack.  */
+          if (template_parameter_pack_p (tparm))
+            {
+              tree arg;
+
+              if (TREE_CODE (tparm) == TEMPLATE_PARM_INDEX)
+                {
+                  arg = make_node (NONTYPE_ARGUMENT_PACK);
+                  TREE_TYPE (arg)  = TREE_TYPE (TEMPLATE_PARM_DECL (tparm));
+                  TREE_CONSTANT (arg) = 1;
+                }
+              else
+                arg = make_node (TYPE_ARGUMENT_PACK);
+
+              SET_ARGUMENT_PACK_ARGS (arg, make_tree_vec (0));
+
+              TREE_VEC_ELT (targs, i) = arg;
+              continue;
+            }
+
          return 2;
        }
 
@@ -12889,7 +13003,7 @@ more_specialized_fn (tree pat1, tree pat2, int len)
 
       if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION)
         {
-          int i, len2 = len + 1;
+          int i, len2 = list_length (args2);
           tree parmvec = make_tree_vec (1);
           tree argvec = make_tree_vec (len2);
           tree ta = args2;
@@ -12913,7 +13027,7 @@ more_specialized_fn (tree pat1, tree pat2, int len)
         }
       else if (TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
         {
-          int i, len1 = len + 1;
+          int i, len1 = list_length (args1);
           tree parmvec = make_tree_vec (1);
           tree argvec = make_tree_vec (len1);
           tree ta = args1;
index a484c05..827f532 100644 (file)
@@ -2283,6 +2283,11 @@ finish_member_declaration (tree decl)
   /* Mark the DECL as a member of the current class.  */
   DECL_CONTEXT (decl) = current_class_type;
 
+  /* Check for bare parameter packs in the member variable declaration.  */
+  if (TREE_CODE (decl) == FIELD_DECL
+      && !check_for_bare_parameter_packs (TREE_TYPE (decl)))
+    TREE_TYPE (decl) == error_mark_node;
+
   /* [dcl.link]
 
      A C language linkage is ignored for the names of class members
index 499acb2..474be38 100644 (file)
@@ -1,3 +1,27 @@
+2007-05-25  Douglas Gregor <doug.gregor@gmail.com>
+
+       PR c++/31431
+       PR c++/31432
+       PR c++/31434
+       PR c++/31435
+       PR c++/31437
+       PR c++/31438
+       PR c++/31442
+       PR c++/31443
+       PR c++/31444
+       PR c++/31445
+       * g++.dg/cpp0x/pr31431.C: New.
+       * g++.dg/cpp0x/pr31437.C: New.
+       * g++.dg/cpp0x/pr31442.C: New.
+       * g++.dg/cpp0x/pr31444.C: New.
+       * g++.dg/cpp0x/pr31431-2.C: New.
+       * g++.dg/cpp0x/pr31432.C: New.
+       * g++.dg/cpp0x/pr31434.C: New.
+       * g++.dg/cpp0x/pr31438.C: New.
+       * g++.dg/cpp0x/pr31443.C: New.
+       * g++.dg/cpp0x/pr31445.C: New.
+       * g++.dg/cpp0x/variadic-crash1.C: New.
+
 2007-05-25  Richard Sandiford  <richard@codesourcery.com>
 
        * gcc.target/arm/long-calls-1.c: New test.
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C b/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C
new file mode 100644 (file)
index 0000000..2f74e38
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-options "-std=gnu++0x" }
+template<typename, typename..., typename> void foo();
+
+void bar()
+{
+  foo<int>(); // { dg-error "no matching function" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31431.C b/gcc/testsuite/g++.dg/cpp0x/pr31431.C
new file mode 100644 (file)
index 0000000..061dab0
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-options "-std=gnu++0x" }
+template<typename..., typename> void foo();
+
+void bar()
+{
+  foo<int>(); // { dg-error "no matching function" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31432.C b/gcc/testsuite/g++.dg/cpp0x/pr31432.C
new file mode 100644 (file)
index 0000000..cb8826e
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-options "-std=gnu++0x" }
+template<typename..., typename> struct A // { dg-error "parameter pack" }
+{
+ static int i;
+};
+
+A<int, int> a; // { dg-error "invalid type" }
+A<char,int> b; // { dg-error "invalid type" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31434.C b/gcc/testsuite/g++.dg/cpp0x/pr31434.C
new file mode 100644 (file)
index 0000000..a785ae9
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-options "-std=gnu++0x" }
+template<typename... T> int foo(const T&) // { dg-error "not expanded with|T" }
+{
+ union { T t; }; // { dg-error "not expanded with|T" }
+ return t;
+}
+
+void bar()
+{
+  foo(0); // { dg-error "no matching" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31437.C b/gcc/testsuite/g++.dg/cpp0x/pr31437.C
new file mode 100644 (file)
index 0000000..0e1a888
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-options "-std=gnu++0x" }
+template <typename... T> struct A
+{ // { dg-error "candidates|A" }
+  A(T* p) {  // { dg-error "parameter packs|T" }
+   (A<T...>*)(p); 
+  }
+};
+
+A<int> a(0); // { dg-error "no matching" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31438.C b/gcc/testsuite/g++.dg/cpp0x/pr31438.C
new file mode 100644 (file)
index 0000000..3a12563
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-options "-std=gnu++0x" }
+
+template<typename> struct A; // { dg-error "candidates" }
+template<typename T, typename... U> struct A<T(U)> // { dg-error "parameter packs|U" }
+{ // { dg-error "parameter packs|U" }
+ template<typename X> A(X); // { dg-error "parameter packs|U" }
+};
+
+A<void(int)> a(0); // { dg-error "no matching" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31442.C b/gcc/testsuite/g++.dg/cpp0x/pr31442.C
new file mode 100644 (file)
index 0000000..050e299
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-options "-std=gnu++0x" }
+template<typename... T, T = 0> struct A {}; // { dg-error "parameter packs|T|the end" }
+
+struct B
+{
+  template <template <typename...> class C> B(C<int>);
+};
+
+B b = A<int>();
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31443.C b/gcc/testsuite/g++.dg/cpp0x/pr31443.C
new file mode 100644 (file)
index 0000000..1eb9d31
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-options "-std=gnu++0x" }
+
+template<int, typename... T> struct A
+{
+  template<int N> void foo(A<N,T>); // { dg-error "parameter packs|T" }
+};
+
+void bar()
+{
+  A<0,int>().foo(A<0,int>()); // { dg-error "no member named" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31444.C b/gcc/testsuite/g++.dg/cpp0x/pr31444.C
new file mode 100644 (file)
index 0000000..b1f86fe
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-options "-std=gnu++0x" }
+template<typename... T> struct A
+{
+  template<int> void foo(A<T>); // { dg-error "not expanded|T" }
+};
+
+void bar()
+{
+  A<int>().foo<0>(A<int>()); // { dg-error "no member named" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31445.C b/gcc/testsuite/g++.dg/cpp0x/pr31445.C
new file mode 100644 (file)
index 0000000..025cb96
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-options "-std=gnu++0x" }
+template <typename... T> struct A
+{
+  void foo(T...); // { dg-error "candidates" }
+  A(T... t) { foo(t); } // { dg-error "parameter packs|t|no matching" }
+};
+
+A<int> a(0);
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-crash1.C b/gcc/testsuite/g++.dg/cpp0x/variadic-crash1.C
new file mode 100644 (file)
index 0000000..f26aee2
--- /dev/null
@@ -0,0 +1,72 @@
+// { dg-options "-std=gnu++0x" }
+
+#define ONE
+#define TWO
+#define THREE
+
+struct Something {};
+Something ___;
+
+template <class F>
+struct Trial
+{
+ F f;
+public:
+ Trial() : f() {}
+ Trial( const F& ff ) : f(ff) { }
+ template <typename... Args>
+ struct Sig { typedef int ResultType; };
+
+ template <typename... Args>
+ struct Sig<Something,Args...> { typedef int ResultType;  };
+
+#ifdef ONE
+
+template <typename... Args>
+typename Sig<Something,Args...>::ResultType operator()(const Something& s, const Args&... args) const
+{
+ return f(args...);
+}
+#endif
+#ifdef TWO
+template <typename... Args>
+typename Sig<Args...>::ResultType operator()(const Args&... args) const
+{
+ return f(args...);
+}
+#endif
+};
+
+struct Internal
+{
+
+template <typename... Args>
+struct Sig { typedef int ResultType; };
+
+template <typename... Args>
+struct Sig<Something,Args...> { typedef int ResultType;  };
+
+template <typename... Args>
+int operator()(const Args&... args) const
+{
+ int n = sizeof...(Args);
+ return n;
+}
+
+ static Trial<Internal>& full() { static Trial<Internal> f; return f; }
+};
+
+static Trial<Internal>& internal = Internal::full();
+
+int main()
+{
+ int n = 0;
+#ifdef ONE
+ n = internal(___,1,2);
+#endif
+#ifdef THREE
+ n = internal(___,1,2,3);
+ n = internal(___,1,2,3,4);
+#endif
+ return 0;
+}