aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDouglas Gregor <doug.gregor@gmail.com>2007-12-18 21:19:41 +0000
committerDoug Gregor <dgregor@gcc.gnu.org>2007-12-18 21:19:41 +0000
commit4cf36211354241794588bab658e807ac550dc9de (patch)
tree23b50a2f189bbdb5981c84f3f3cf60d440a43c0a /gcc
parent3615b8c2004057ce9cc64a449d0f9a88214e8997 (diff)
downloadgcc-4cf36211354241794588bab658e807ac550dc9de.zip
gcc-4cf36211354241794588bab658e807ac550dc9de.tar.gz
gcc-4cf36211354241794588bab658e807ac550dc9de.tar.bz2
re PR c++/32565 (ICE with specialization of variadic template)
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.c156
-rw-r--r--gcc/testsuite/ChangeLog12
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic84.C26
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic85.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic86.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic87.C23
-rw-r--r--gcc/testsuite/g++.dg/template/ttp25.C26
7 files changed, 260 insertions, 12 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b64ccf8..011ef2f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d414b13..02f906b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..d5be764
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic84.C
@@ -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
index 0000000..7004d08
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic85.C
@@ -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
index 0000000..d8fcd62
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic86.C
@@ -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
index 0000000..1defa23
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic87.C
@@ -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
index 0000000..8915303
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp25.C
@@ -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>());
+}