diff options
author | Douglas Gregor <doug.gregor@gmail.com> | 2007-12-18 21:19:41 +0000 |
---|---|---|
committer | Doug Gregor <dgregor@gcc.gnu.org> | 2007-12-18 21:19:41 +0000 |
commit | 4cf36211354241794588bab658e807ac550dc9de (patch) | |
tree | 23b50a2f189bbdb5981c84f3f3cf60d440a43c0a /gcc | |
parent | 3615b8c2004057ce9cc64a449d0f9a88214e8997 (diff) | |
download | gcc-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.c | 156 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/variadic84.C | 26 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/variadic85.C | 10 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/variadic86.C | 19 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/variadic87.C | 23 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/ttp25.C | 26 |
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>()); +} |