re PR c++/32565 (ICE with specialization of variadic template)
authorDouglas Gregor <doug.gregor@gmail.com>
Tue, 18 Dec 2007 21:19:41 +0000 (21:19 +0000)
committerDoug Gregor <dgregor@gcc.gnu.org>
Tue, 18 Dec 2007 21:19:41 +0000 (21:19 +0000)
2007-12-18  Douglas Gregor  <doug.gregor@gmail.com>
            Jakub Jelinek  <jakub@redhat.com>

PR c++/32565
PR c++/33943
PR c++/33965
* pt.c (template_template_parm_bindings_ok_p): New; verifies
bindings of template template parameters after all template
arguments have been deduced.
(coerce_template_parms): Don't complain when COMPLAIN doesn't
include tf_error.
(fn_type_unification): Use template_template_parm_bindings_ok_p.
(unify): Deal with variadic, bound template template parameters.
(get_class_bindings): Use template_template_parm_bindings_ok_p.

2007-12-18  Douglas Gregor  <doug.gregor@gmail.com>
    Jakub Jelinek  <jakub@redhat.com>

PR c++/32565
PR c++/33943
PR c++/33965
* g++.dg/cpp0x/variadic86.C: New.
* g++.dg/cpp0x/variadic87.C: New.
* g++.dg/cpp0x/variadic84.C: New.
* g++.dg/cpp0x/variadic85.C: New.
* g++.dg/template/ttp25.C: New.

Co-Authored-By: Jakub Jelinek <jakub@redhat.com>
From-SVN: r131041

gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/variadic84.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/variadic85.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/variadic86.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/variadic87.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/ttp25.C [new file with mode: 0644]

index b64ccf83c56330429632ddfb03bcd8fe47fb1d99..011ef2fbc032c56541f76c0167ad63f8e262f5ea 100644 (file)
@@ -158,6 +158,7 @@ static tree get_template_base (tree, tree, tree, tree);
 static tree try_class_unification (tree, tree, tree, tree);
 static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
                                           tree, tree);
+static bool template_template_parm_bindings_ok_p (tree, tree);
 static int template_args_equal (tree, tree);
 static void tsubst_default_arguments (tree);
 static tree for_each_template_parm_r (tree *, int *, void *);
@@ -4750,6 +4751,77 @@ coerce_template_template_parms (tree parm_parms,
   return 1;
 }
 
+/* Verifies that the deduced template arguments (in TARGS) for the
+   template template parameters (in TPARMS) represent valid bindings,
+   by comparing the template parameter list of each template argument
+   to the template parameter list of its corresponding template
+   template parameter, in accordance with DR150. This
+   routine can only be called after all template arguments have been
+   deduced. It will return TRUE if all of the template template
+   parameter bindings are okay, FALSE otherwise.  */
+bool 
+template_template_parm_bindings_ok_p (tree tparms, tree targs)
+{
+  int i, ntparms = TREE_VEC_LENGTH (tparms);
+
+  targs = INNERMOST_TEMPLATE_ARGS (targs);
+
+  for (i = 0; i < ntparms; ++i)
+    {
+      tree tparm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
+      tree targ = TREE_VEC_ELT (targs, i);
+
+      if (TREE_CODE (tparm) == TEMPLATE_DECL && targ)
+       {
+         tree packed_args = NULL_TREE;
+         int idx, len = 1;
+
+         if (ARGUMENT_PACK_P (targ))
+           {
+             /* Look inside the argument pack.  */
+             packed_args = ARGUMENT_PACK_ARGS (targ);
+             len = TREE_VEC_LENGTH (packed_args);
+           }
+
+         for (idx = 0; idx < len; ++idx)
+           {
+             tree targ_parms = NULL_TREE;
+
+             if (packed_args)
+               /* Extract the next argument from the argument
+                  pack.  */
+               targ = TREE_VEC_ELT (packed_args, idx);
+
+             if (PACK_EXPANSION_P (targ))
+               /* Look at the pattern of the pack expansion.  */
+               targ = PACK_EXPANSION_PATTERN (targ);
+
+             /* Extract the template parameters from the template
+                argument.  */
+             if (TREE_CODE (targ) == TEMPLATE_DECL)
+               targ_parms = DECL_INNERMOST_TEMPLATE_PARMS (targ);
+             else if (TREE_CODE (targ) == TEMPLATE_TEMPLATE_PARM)
+               targ_parms = DECL_INNERMOST_TEMPLATE_PARMS (TYPE_NAME (targ));
+
+             /* Verify that we can coerce the template template
+                parameters from the template argument to the template
+                parameter.  This requires an exact match.  */
+             if (targ_parms
+                 && !coerce_template_template_parms
+                      (DECL_INNERMOST_TEMPLATE_PARMS (tparm),
+                       targ_parms,
+                       tf_none,
+                       tparm,
+                       targs))
+               return false;
+           }
+       }
+    }
+
+  /* Everything is okay.  */
+  return true;
+}
+
 /* Convert the indicated template ARG as necessary to match the
    indicated template PARM.  Returns the converted ARG, or
    error_mark_node if the conversion was unsuccessful.  Error and
@@ -5183,16 +5255,19 @@ coerce_template_parms (tree parms,
 
           if (arg && PACK_EXPANSION_P (arg))
             {
-              /* 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.  */
-              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 (complain & tf_error)
+               {
+                 /* 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.  */
+                 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);
+               }
              return error_mark_node;
             }
         }
@@ -11627,6 +11702,32 @@ fn_type_unification (tree fn,
         }
     }
 
+  /* Now that we have bindings for all of the template arguments,
+     ensure that the arguments deduced for the template template
+     parameters have compatible template parameter lists.  We cannot
+     check this property before we have deduced all template
+     arguments, because the template parameter types of a template
+     template parameter might depend on prior template parameters
+     deduced after the template template parameter.  The following
+     ill-formed example illustrates this issue:
+
+       template<typename T, template<T> class C> void f(C<5>, T);
+
+       template<int N> struct X {};
+
+       void g() {
+         f(X<5>(), 5l); // error: template argument deduction fails
+       }
+
+     The template parameter list of 'C' depends on the template type
+     parameter 'T', but 'C' is deduced to 'X' before 'T' is deduced to
+     'long'.  Thus, we can't check that 'C' cannot bind to 'X' at the
+     time that we deduce 'C'.  */
+  if (result == 0
+      && !template_template_parm_bindings_ok_p 
+           (DECL_INNERMOST_TEMPLATE_PARMS (fn), targs))
+    return 1;
+
   if (result == 0)
     /* All is well so far.  Now, check:
 
@@ -12711,7 +12812,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
            tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));
            tree argtmplvec
              = DECL_INNERMOST_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (arg));
-           int i;
+           int i, len;
+            int parm_variadic_p = 0;
 
            /* The resolution to DR150 makes clear that default
               arguments for an N-argument may not be used to bind T
@@ -12753,7 +12855,21 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
               rather than the whole TREE_VEC since they can have
               different number of elements.  */
 
-           for (i = 0; i < TREE_VEC_LENGTH (parmvec); ++i)
+            parmvec = expand_template_argument_pack (parmvec);
+            argvec = expand_template_argument_pack (argvec);
+
+            len = TREE_VEC_LENGTH (parmvec);
+
+            /* Check if the parameters end in a pack, making them
+               variadic.  */
+            if (len > 0
+                && PACK_EXPANSION_P (TREE_VEC_ELT (parmvec, len - 1)))
+              parm_variadic_p = 1;
+            
+            if (TREE_VEC_LENGTH (argvec) < len - parm_variadic_p)
+              return 1;
+
+             for (i = 0; i < len - parm_variadic_p; ++i)
              {
                if (unify (tparms, targs,
                           TREE_VEC_ELT (parmvec, i),
@@ -12761,6 +12877,14 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
                           UNIFY_ALLOW_NONE))
                  return 1;
              }
+
+           if (parm_variadic_p
+               && unify_pack_expansion (tparms, targs,
+                                        parmvec, argvec,
+                                        UNIFY_ALLOW_NONE,
+                                        /*call_args_p=*/false,
+                                        /*subr=*/false))
+             return 1;
          }
          arg = TYPE_TI_TEMPLATE (arg);
 
@@ -13783,6 +13907,14 @@ get_class_bindings (tree tparms, tree spec_args, tree args)
                              INNERMOST_TEMPLATE_ARGS (args)))
     return NULL_TREE;
 
+  /* Now that we have bindings for all of the template arguments,
+     ensure that the arguments deduced for the template template
+     parameters have compatible template parameter lists.  See the use
+     of template_template_parm_bindings_ok_p in fn_type_unification
+     for more information.  */
+  if (!template_template_parm_bindings_ok_p (tparms, deduced_args))
+    return NULL_TREE;
+
   return deduced_args;
 }
 
index d414b13ddc184de1c561769e1791752615df80c5..02f906bd06bf1e71bc8df313747b3f8c509b3994 100644 (file)
@@ -1,3 +1,15 @@
+2007-12-18  Douglas Gregor  <doug.gregor@gmail.com>
+           Jakub Jelinek  <jakub@redhat.com>
+       
+       PR c++/32565
+       PR c++/33943
+       PR c++/33965
+       * g++.dg/cpp0x/variadic86.C: New.
+       * g++.dg/cpp0x/variadic87.C: New.
+       * g++.dg/cpp0x/variadic84.C: New.
+       * g++.dg/cpp0x/variadic85.C: New.
+       * g++.dg/template/ttp25.C: New.
+
 2007-12-18  Sebastian Pop  <sebastian.pop@amd.com>
 
        PR tree-optimization/34123
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic84.C b/gcc/testsuite/g++.dg/cpp0x/variadic84.C
new file mode 100644 (file)
index 0000000..d5be764
--- /dev/null
@@ -0,0 +1,26 @@
+// PR c++/32565
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+template<typename...> struct A1;
+template<template<int...> class T> struct A1<T<0> > {};
+template<typename...> struct A2;
+template<template<int...> class T> struct A2<T<0, 1> > {};
+template<typename...> struct A3;
+template<template<int, int...> class T> struct A3<T<0, 1> > {};
+template<typename...> struct A4;
+template<template<typename...> class T> struct A4<T<int> > {};
+template<typename...> struct A5;
+template<template<typename...> class T> struct A5<T<int, long> > {};
+template<typename...> struct A6;
+template<template<typename, typename...> class T> struct A6<T<int, long> > {};
+template<int> struct B1 {};
+template<int, int> struct B2 {};
+template<typename> struct B3 {};
+template<typename, typename> struct B4 {};
+A1<B1<0> > a1; // { dg-error "incomplete type" }
+A2<B2<0, 1> > a2; // { dg-error "incomplete type" }
+A3<B2<0, 1> > a3; // { dg-error "incomplete type" }
+A4<B3<int> > a4; // { dg-error "incomplete type" }
+A5<B4<int, long> > a5; // { dg-error "incomplete type" }
+A6<B4<int, long> > a6; // { dg-error "incomplete type" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic85.C b/gcc/testsuite/g++.dg/cpp0x/variadic85.C
new file mode 100644 (file)
index 0000000..7004d08
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/32565
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+template<typename...> struct A1;
+template<template<int, int...> class T> struct A1<T<0, 1> > {};
+template<int, int, int...> struct B1 {};
+A1<B1<0, 1> > a1; // { dg-error "incomplete type" }
+template<int...> struct B2 {};
+A1<B2<0, 1> > a2; // { dg-error "incomplete type" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic86.C b/gcc/testsuite/g++.dg/cpp0x/variadic86.C
new file mode 100644 (file)
index 0000000..d8fcd62
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/33943
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+template<typename... A> struct foo {};
+
+template<typename A0, typename... A1> struct bar {};
+
+template<typename U> struct baz;
+
+template<template<typename...> class T, typename... U> struct baz< T<U...> >
+{};
+
+template<template<typename, typename...> class T, typename U, typename... V>
+struct baz< T<U, V...> >
+{};
+
+baz< foo<int, short> > b1;
+baz< bar<int, short> > b2;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic87.C b/gcc/testsuite/g++.dg/cpp0x/variadic87.C
new file mode 100644 (file)
index 0000000..1defa23
--- /dev/null
@@ -0,0 +1,23 @@
+// PR c++/33965
+// { dg-options -std=c++0x }
+template<typename T>
+struct foo
+{
+    static bool const value = false;
+};
+
+template<template<typename...> class T, typename... Args>
+struct foo<T<Args...> >
+{
+    static bool const value = true;
+};
+
+template<int I>
+struct int_
+{};
+
+int main()
+{
+  static_assert(foo<int_<0> >::value == false, 
+               "picked up partial specialization, but should not have");
+}
diff --git a/gcc/testsuite/g++.dg/template/ttp25.C b/gcc/testsuite/g++.dg/template/ttp25.C
new file mode 100644 (file)
index 0000000..8915303
--- /dev/null
@@ -0,0 +1,26 @@
+// { dg-do compile }
+template<typename T, template<T> class C>
+void f1(T, C<5>);
+
+template<typename T, template<T> class C>
+void f2(C<5>, T);
+
+template<typename T, template<T> class C>
+void f3(C<5>, T);
+
+template<typename T> struct metafun { typedef T type; };
+
+template<> struct metafun<short> { typedef int type; };
+
+template<typename T, template<typename metafun<T>::type> class C>
+void f4(T, C<5>);
+
+template<int N> struct X {};
+void g() {
+  f1(5l, X<5>()); // { dg-error "no matching" }
+  f2(X<5>(), 5);
+  f3(X<5>(), 5l); // { dg-error "no matching" }
+  f4(5, X<5>());
+  f4(5l, X<5>()); // { dg-error "no matching" }
+  f4((short)5, X<5>());
+}