Here we set "lost" and then returned error_mark_node without ever actually giving an error, because the comment that !arg only occurred with a previous error was wrong (and lacked an assert (seen_error())).
We already had code for dealing with the case of fixed packs and too many arguments, but not for too few. With this patch we now calculate the actual number of arguments expected as we go along and adjust them; if we end up with the wrong number, we can give an error at the end. Tested x86_64-pc-linux-gnu, applying to trunk.
commit f7f58d8bee895207d10a776a72f8c33da3e648cb Author: Jason Merrill <ja...@redhat.com> Date: Fri Mar 16 16:15:45 2018 -0400 PR c++/71834 - template-id with too few arguments. * pt.c (coerce_template_parms): Check fixed_parameter_pack_p. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 745c9acd6ee..abdb77f826a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8234,6 +8234,11 @@ coerce_template_parms (tree parms, int variadic_args_p = 0; int post_variadic_parms = 0; + /* Adjustment to nparms for fixed parameter packs. */ + int fixed_pack_adjust = 0; + int fixed_packs = 0; + int missing = 0; + /* Likewise for parameters with default arguments. */ int default_p = 0; @@ -8278,6 +8283,7 @@ coerce_template_parms (tree parms, || (TREE_VEC_ELT (parms, nargs) != error_mark_node && !TREE_PURPOSE (TREE_VEC_ELT (parms, nargs)))))) { + bad_nargs: if (complain & tf_error) { if (variadic_p || default_p) @@ -8389,11 +8395,17 @@ coerce_template_parms (tree parms, lost++; /* We are done with all of the arguments. */ arg_idx = nargs; + break; } else { pack_adjust = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) - 1; arg_idx += pack_adjust; + if (fixed_parameter_pack_p (TREE_VALUE (parm))) + { + ++fixed_packs; + fixed_pack_adjust += pack_adjust; + } } continue; @@ -8451,12 +8463,18 @@ coerce_template_parms (tree parms, error ("template argument %d is invalid", arg_idx + 1); } else if (!arg) - /* This only occurs if there was an error in the template - parameter list itself (which we would already have - reported) that we are trying to recover from, e.g., a class - template with a parameter list such as - template<typename..., typename>. */ - ++lost; + { + /* This can occur if there was an error in the template + parameter list itself (which we would already have + reported) that we are trying to recover from, e.g., a class + template with a parameter list such as + template<typename..., typename> (cpp0x/variadic150.C). */ + ++lost; + + /* This can also happen with a fixed parameter pack (71834). */ + if (arg_idx >= nargs) + ++missing; + } else arg = convert_template_argument (TREE_VALUE (parm), arg, new_args, complain, @@ -8469,20 +8487,20 @@ coerce_template_parms (tree parms, cp_unevaluated_operand = saved_unevaluated_operand; c_inhibit_evaluation_warnings = saved_inhibit_evaluation_warnings; - if (variadic_p && arg_idx < nargs) + if (missing || arg_idx < nargs - variadic_args_p) { - if (complain & tf_error) - { - error ("wrong number of template arguments " - "(%d, should be %d)", nargs, arg_idx); - if (in_decl) - error ("provided for %q+D", in_decl); - } - return error_mark_node; + /* If we had fixed parameter packs, we didn't know how many arguments we + actually needed earlier; now we do. */ + nparms += fixed_pack_adjust; + variadic_p -= fixed_packs; + goto bad_nargs; } if (lost) - return error_mark_node; + { + gcc_assert (!(complain & tf_error) || seen_error ()); + return error_mark_node; + } if (CHECKING_P && !NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args)) SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args, diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-nested3.C b/gcc/testsuite/g++.dg/cpp0x/variadic-nested3.C new file mode 100644 index 00000000000..381ff731c09 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-nested3.C @@ -0,0 +1,10 @@ +// PR c++/71834 +// { dg-do compile { target c++11 } } + +template < typename ... Ts > struct A +{ + template < Ts ..., typename U > struct B {}; +}; + +// should be, e.g.: A < int >::B < 0, int > e; +A < int >::B < 0 > e; // { dg-error "wrong number of template arguments" }