From: Douglas Gregor Date: Tue, 18 Dec 2007 21:19:41 +0000 (+0000) Subject: re PR c++/32565 (ICE with specialization of variadic template) X-Git-Tag: releases/gcc-4.3.0~907 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4cf36211354241794588bab658e807ac550dc9de;p=thirdparty%2Fgcc.git re PR c++/32565 (ICE with specialization of variadic template) 2007-12-18 Douglas Gregor Jakub Jelinek 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 Jakub Jelinek 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 From-SVN: r131041 --- diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b64ccf83c563..011ef2fbc032 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 class C> void f(C<5>, T); + + template 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 d414b13ddc18..02f906bd06bf 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2007-12-18 Douglas Gregor + Jakub Jelinek + + 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 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 000000000000..d5be7646156b --- /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 struct A1; +template class T> struct A1 > {}; +template struct A2; +template class T> struct A2 > {}; +template struct A3; +template class T> struct A3 > {}; +template struct A4; +template class T> struct A4 > {}; +template struct A5; +template class T> struct A5 > {}; +template struct A6; +template class T> struct A6 > {}; +template struct B1 {}; +template struct B2 {}; +template struct B3 {}; +template struct B4 {}; +A1 > a1; // { dg-error "incomplete type" } +A2 > a2; // { dg-error "incomplete type" } +A3 > a3; // { dg-error "incomplete type" } +A4 > a4; // { dg-error "incomplete type" } +A5 > a5; // { dg-error "incomplete type" } +A6 > 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 000000000000..7004d086a0f6 --- /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 struct A1; +template class T> struct A1 > {}; +template struct B1 {}; +A1 > a1; // { dg-error "incomplete type" } +template struct B2 {}; +A1 > 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 000000000000..d8fcd620e95f --- /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 struct foo {}; + +template struct bar {}; + +template struct baz; + +template class T, typename... U> struct baz< T > +{}; + +template class T, typename U, typename... V> +struct baz< T > +{}; + +baz< foo > b1; +baz< bar > b2; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic87.C b/gcc/testsuite/g++.dg/cpp0x/variadic87.C new file mode 100644 index 000000000000..1defa23da292 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic87.C @@ -0,0 +1,23 @@ +// PR c++/33965 +// { dg-options -std=c++0x } +template +struct foo +{ + static bool const value = false; +}; + +template class T, typename... Args> +struct foo > +{ + static bool const value = true; +}; + +template +struct int_ +{}; + +int main() +{ + static_assert(foo >::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 000000000000..89153037913c --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp25.C @@ -0,0 +1,26 @@ +// { dg-do compile } +template class C> +void f1(T, C<5>); + +template class C> +void f2(C<5>, T); + +template class C> +void f3(C<5>, T); + +template struct metafun { typedef T type; }; + +template<> struct metafun { typedef int type; }; + +template::type> class C> +void f4(T, C<5>); + +template 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>()); +}