re PR c++/48322 ([C++0x] Plural variadic parameter packs are not expanded well)
authorJason Merrill <jason@redhat.com>
Mon, 21 Nov 2011 02:04:54 +0000 (21:04 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 21 Nov 2011 02:04:54 +0000 (21:04 -0500)
PR c++/48322
gcc/cp/
* cp-tree.h (PACK_EXPANSION_EXTRA_ARGS): New.
* cp-tree.def (EXPR_PACK_EXPANSION): Add an operand for it.
* pt.c (tsubst_pack_expansion): Set and use it.
(iterative_hash_template_arg): Hash it.
(template_args_equal): Compare it.
(comp_template_args_with_info): Handle nulls.
* tree.c (cp_walk_subtrees): Walk it.
* typeck.c (structural_comptypes): Compare it.
* ptree.c (cxx_print_type): Print it.
libstdc++-v3/
* include/std/tuple (tuple(_UElements&&...)): Fix SFINAE.

From-SVN: r181547

12 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/cp/ptree.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/sfinae26.C
gcc/testsuite/g++.dg/cpp0x/variadic120.C [new file with mode: 0644]
libstdc++-v3/ChangeLog
libstdc++-v3/include/std/tuple

index 21bfbcd2ebd820a07e4d30e664acd20c1cf120b7..93cd960a61139535f0cbc6fc1978056c289eec6a 100644 (file)
@@ -1,5 +1,16 @@
 2011-11-20  Jason Merrill  <jason@redhat.com>
 
+       PR c++/48322
+       * cp-tree.h (PACK_EXPANSION_EXTRA_ARGS): New.
+       * cp-tree.def (EXPR_PACK_EXPANSION): Add an operand for it.
+       * pt.c (tsubst_pack_expansion): Set and use it.
+       (iterative_hash_template_arg): Hash it.
+       (template_args_equal): Compare it.
+       (comp_template_args_with_info): Handle nulls.
+       * tree.c (cp_walk_subtrees): Walk it.
+       * typeck.c (structural_comptypes): Compare it.
+       * ptree.c (cxx_print_type): Print it.
+
        * pt.c (type_unification_real): Set input_location
        during default arg instantiation.
 
index 4eec9f97c7d1ee3ad81cf162f3919f73130bd10a..5fc5496ef9e2fd0d12ebd758b1e4a87329d852f4 100644 (file)
@@ -419,7 +419,7 @@ DEFTREECODE (TYPE_PACK_EXPANSION, "type_pack_expansion", tcc_type, 0)
 
    EXPR_PACK_EXPANSION plays precisely the same role as TYPE_PACK_EXPANSION,
    but will be used for expressions.  */
-DEFTREECODE (EXPR_PACK_EXPANSION, "expr_pack_expansion", tcc_expression, 2)
+DEFTREECODE (EXPR_PACK_EXPANSION, "expr_pack_expansion", tcc_expression, 3)
 
 /* Selects the Ith parameter out of an argument pack. This node will
    be used when instantiating pack expansions; see
index fe50e34e7d9ea12c97c937a322aad0f64f081ee6..3f4f4081f38e5a8652b962498aa304d119a19467 100644 (file)
@@ -2813,7 +2813,14 @@ extern void decl_shadowed_for_var_insert (tree, tree);
 #define PACK_EXPANSION_PARAMETER_PACKS(NODE)           \
   *(TREE_CODE (NODE) == EXPR_PACK_EXPANSION            \
     ? &TREE_OPERAND (NODE, 1)                          \
-    : &TREE_CHAIN (TYPE_PACK_EXPANSION_CHECK (NODE)))
+    : &TYPE_MINVAL (TYPE_PACK_EXPANSION_CHECK (NODE)))
+
+/* Any additional template args to be applied when substituting into
+   the pattern, set by tsubst_pack_expansion for partial instantiations.  */
+#define PACK_EXPANSION_EXTRA_ARGS(NODE)                \
+  *(TREE_CODE (NODE) == TYPE_PACK_EXPANSION    \
+    ? &TYPE_MAXVAL (NODE)                      \
+    : &TREE_OPERAND ((NODE), 2))
 
 /* Determine if this is an argument pack.  */
 #define ARGUMENT_PACK_P(NODE)                          \
index 5b39e9fbb4291a803905b0e7c0e14081036e8e3a..f0ee0c5f17e5da7bfedacbcfc17fda180e554b92 100644 (file)
@@ -1534,7 +1534,8 @@ iterative_hash_template_arg (tree arg, hashval_t val)
 
     case TYPE_PACK_EXPANSION:
     case EXPR_PACK_EXPANSION:
-      return iterative_hash_template_arg (PACK_EXPANSION_PATTERN (arg), val);
+      val = iterative_hash_template_arg (PACK_EXPANSION_PATTERN (arg), val);
+      return iterative_hash_template_arg (PACK_EXPANSION_EXTRA_ARGS (arg), val);
 
     case TYPE_ARGUMENT_PACK:
     case NONTYPE_ARGUMENT_PACK:
@@ -6902,9 +6903,11 @@ template_args_equal (tree ot, tree nt)
     /* For member templates */
     return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
   else if (PACK_EXPANSION_P (ot))
-    return PACK_EXPANSION_P (nt) 
-      && template_args_equal (PACK_EXPANSION_PATTERN (ot),
-                              PACK_EXPANSION_PATTERN (nt));
+    return (PACK_EXPANSION_P (nt)
+           && template_args_equal (PACK_EXPANSION_PATTERN (ot),
+                                   PACK_EXPANSION_PATTERN (nt))
+           && template_args_equal (PACK_EXPANSION_EXTRA_ARGS (ot),
+                                   PACK_EXPANSION_EXTRA_ARGS (nt)));
   else if (ARGUMENT_PACK_P (ot))
     {
       int i, len;
@@ -6954,6 +6957,12 @@ comp_template_args_with_info (tree oldargs, tree newargs,
 {
   int i;
 
+  if (oldargs == newargs)
+    return 1;
+
+  if (!oldargs || !newargs)
+    return 0;
+
   if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs))
     return 0;
 
@@ -9241,13 +9250,21 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
   tree pattern;
   tree pack, packs = NULL_TREE;
   bool unsubstituted_packs = false;
+  bool real_packs = false;
+  int missing_level = 0;
   int i, len = -1;
   tree result;
   htab_t saved_local_specializations = NULL;
+  int levels;
 
   gcc_assert (PACK_EXPANSION_P (t));
   pattern = PACK_EXPANSION_PATTERN (t);
 
+  /* Add in any args remembered from an earlier partial instantiation.  */
+  args = add_to_template_args (PACK_EXPANSION_EXTRA_ARGS (t), args);
+
+  levels = TMPL_ARGS_DEPTH (args);
+
   /* Determine the argument packs that will instantiate the parameter
      packs used in the expansion expression. While we're at it,
      compute the number of arguments to be expanded and make sure it
@@ -9258,6 +9275,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
       tree parm_pack = TREE_VALUE (pack);
       tree arg_pack = NULL_TREE;
       tree orig_arg = NULL_TREE;
+      int level = 0;
 
       if (TREE_CODE (parm_pack) == BASES)
        {
@@ -9290,10 +9308,9 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
        }
       else
         {
-          int level, idx, levels;
+         int idx;
           template_parm_level_and_index (parm_pack, &level, &idx);
 
-          levels = TMPL_ARGS_DEPTH (args);
           if (level <= levels)
             arg_pack = TMPL_ARG (args, level, idx);
         }
@@ -9344,6 +9361,13 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
               return error_mark_node;
             }
 
+         if (TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1
+             && PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack),
+                                                0)))
+           /* This isn't a real argument pack yet.  */;
+         else
+           real_packs = true;
+
           /* Keep track of the parameter packs and their corresponding
              argument packs.  */
           packs = tree_cons (parm_pack, arg_pack, packs);
@@ -9351,25 +9375,57 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
         }
       else
        {
-         /* We can't substitute for this parameter pack.  */
+         /* We can't substitute for this parameter pack.  We use a flag as
+            well as the missing_level counter because function parameter
+            packs don't have a level.  */
          unsubstituted_packs = true;
-         break;
+         if (!missing_level || missing_level > level)
+           missing_level = level;
        }
     }
 
   /* We cannot expand this expansion expression, because we don't have
-     all of the argument packs we need. Substitute into the pattern
-     and return a PACK_EXPANSION_*. The caller will need to deal with
-     that.  */
+     all of the argument packs we need.  */
   if (unsubstituted_packs)
     {
-      tree new_pat;
-      if (TREE_CODE (t) == EXPR_PACK_EXPANSION)
-       new_pat = tsubst_expr (pattern, args, complain, in_decl,
-                              /*integral_constant_expression_p=*/false);
+      if (real_packs)
+       {
+         /* We got some full packs, but we can't substitute them in until we
+            have values for all the packs.  So remember these until then.  */
+         tree save_args;
+
+         t = make_pack_expansion (pattern);
+
+         /* The call to add_to_template_args above assumes no overlap
+            between saved args and new args, so prune away any fake
+            args, i.e. those that satisfied arg_from_parm_pack_p above.  */
+         if (missing_level && levels >= missing_level)
+           {
+             gcc_assert (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)
+                         && missing_level > 1);
+             TREE_VEC_LENGTH (args) = missing_level - 1;
+             save_args = copy_node (args);
+             TREE_VEC_LENGTH (args) = levels;
+           }
+         else
+           save_args = args;
+
+         PACK_EXPANSION_EXTRA_ARGS (t) = save_args;
+       }
       else
-       new_pat = tsubst (pattern, args, complain, in_decl);
-      return make_pack_expansion (new_pat);
+       {
+         /* There were no real arguments, we're just replacing a parameter
+            pack with another version of itself. Substitute into the
+            pattern and return a PACK_EXPANSION_*. The caller will need to
+            deal with that.  */
+         if (TREE_CODE (t) == EXPR_PACK_EXPANSION)
+           t = tsubst_expr (pattern, args, complain, in_decl,
+                            /*integral_constant_expression_p=*/false);
+         else
+           t = tsubst (pattern, args, complain, in_decl);
+         t = make_pack_expansion (t);
+       }
+      return t;
     }
 
   /* We could not find any argument packs that work.  */
index fb05e13604506414f3928b25c60c34e2588e5bdd..a66e695c1f746505a578eef27983a4834fe36945 100644 (file)
@@ -104,6 +104,10 @@ cxx_print_type (FILE *file, tree node, int indent)
                  indent + 4);
       return;
 
+    case TYPE_PACK_EXPANSION:
+      print_node (file, "args", PACK_EXPANSION_EXTRA_ARGS (node), indent + 4);
+      return;
+
     default:
       return;
     }
index 841029f3385880786dde11b93b3357b22e47ac0a..d206fd2ec2480cf40c6bc9392a707222e1ad5835 100644 (file)
@@ -2993,11 +2993,13 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
 
     case TYPE_PACK_EXPANSION:
       WALK_SUBTREE (TREE_TYPE (*tp));
+      WALK_SUBTREE (PACK_EXPANSION_EXTRA_ARGS (*tp));
       *walk_subtrees_p = 0;
       break;
       
     case EXPR_PACK_EXPANSION:
       WALK_SUBTREE (TREE_OPERAND (*tp, 0));
+      WALK_SUBTREE (PACK_EXPANSION_EXTRA_ARGS (*tp));
       *walk_subtrees_p = 0;
       break;
 
index b8d4c10c8ca29687dcee1ba56b95c9ec2151b97a..a23e27491d8c8056290d6504bf3b78d605b51ce9 100644 (file)
@@ -1329,8 +1329,10 @@ structural_comptypes (tree t1, tree t2, int strict)
       break;
 
     case TYPE_PACK_EXPANSION:
-      return same_type_p (PACK_EXPANSION_PATTERN (t1), 
-                          PACK_EXPANSION_PATTERN (t2));
+      return (same_type_p (PACK_EXPANSION_PATTERN (t1),
+                          PACK_EXPANSION_PATTERN (t2))
+             && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1),
+                                    PACK_EXPANSION_EXTRA_ARGS (t2)));
 
     case DECLTYPE_TYPE:
       if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
index 57ed126332ef4102afa948dc3d45924d5b576f6a..58a3ff0aaf680e1b7e73afa2e7f589581889eb48 100644 (file)
@@ -1,5 +1,9 @@
 2011-11-20  Jason Merrill  <jason@redhat.com>
 
+       PR c++/48322
+       * g++.dg/cpp0x/variadic120.C: New.
+       * g++.dg/cpp0x/sfinae26.C: Adjust.
+
        * g++.dg/cpp0x/sfinae11.C: Adjust.
        * g++.dg/cpp0x/sfinae26.C: Adjust.
        * g++.dg/template/unify11.C: Adjust.
index 42b48eb5a6b27a49a61e102a68fe84098d17d671..374f9976b2c95f84c90a5d7b6e40ecc7772783f9 100644 (file)
@@ -30,9 +30,9 @@ struct is_same<T, T> {
 template<class... T>
 struct S {
   template<class... U,
-    typename enable_if<and_<is_same<T, U>...>::value>::type*& = enabler
+    typename enable_if<and_<is_same<T, U>...>::value>::type*& = enabler // { dg-error "no type" }
   >
-  S(U...){}                    // { dg-error "no type named 'type'" }
+  S(U...){}
 };
 
 S<bool> s(0);                  // { dg-error "no match" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic120.C b/gcc/testsuite/g++.dg/cpp0x/variadic120.C
new file mode 100644 (file)
index 0000000..e26ee4e
--- /dev/null
@@ -0,0 +1,24 @@
+// PR c++/48322
+// { dg-do compile { target c++11 } }
+
+template <class... T> struct tuple;
+template <class T> struct tuple<T> { T t; };
+
+template <class T, class U> struct pair;
+template<> struct pair<int,double> { };
+
+template <class... Ts>
+struct A
+{
+  template <class... Us,
+            class V = tuple<pair<Ts,Us>...> >
+  static void f()
+  {
+    V v;
+  }
+};
+
+int main()
+{
+  A<int>::f<double>();
+}
index 282e95b1fa3ab8bf4b3a77107d05b4d7763c1790..336e77f8c0afb9ad180374b11c72558450cde9a8 100644 (file)
@@ -1,5 +1,8 @@
 2011-11-20  Jason Merrill  <jason@redhat.com>
 
+       PR c++/48322
+       * include/std/tuple (tuple(_UElements&&...)): Fix SFINAE.
+
        * testsuite/20_util/bind/ref_neg.cc: Adjust error markings.
 
 2011-11-20  Jonathan Wakely  <jwakely.gcc@gmail.com>
index 51be289d506d1bc970d2dfa72f09841b2445aaa3..474634fc24e8b6b33ae650a85f1950d148b21ac4 100644 (file)
@@ -407,12 +407,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr tuple(const _Elements&... __elements)
       : _Inherited(__elements...) { }
 
-      template<typename... _UElements, typename = typename
-       enable_if<__and_<integral_constant<bool, sizeof...(_UElements)
-                                          == sizeof...(_Elements)>,
-                        __all_convertible<__conv_types<_UElements...>,
-                                          __conv_types<_Elements...>>
-                        >::value>::type>
+      template<typename... _UElements,
+              typename = typename enable_if<sizeof...(_UElements)
+                                            == sizeof...(_Elements)>::type,
+              typename = typename
+                enable_if<__all_convertible<__conv_types<_UElements...>,
+                                            __conv_types<_Elements...> >::value
+                          >::type>
        explicit
         constexpr tuple(_UElements&&... __elements)
        : _Inherited(std::forward<_UElements>(__elements)...) { }