cp_parser_check_template_parameters is supposed to catch when we have the wrong number of template parameter lists, but it wasn't diagnosing this case. Fixed by checking whether the thing we're declaring used a template-id; the case of declaring a primary template, when we allow one more template parameter list, uses a plain identifier.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 770f6eaf7320d908cd39ace3aa155e7ec829982d Author: Jason Merrill <ja...@redhat.com> Date: Mon Apr 9 14:03:15 2018 -0400 PR c++/85264 - ICE with excess template-parameter-list. * parser.c (cp_parser_check_template_parameters): Add template_id_p parameter. Don't allow an extra template header if true. (cp_parser_class_head): Pass template_id_p. (cp_parser_elaborated_type_specifier): Likewise. (cp_parser_alias_declaration): Likewise. (cp_parser_check_declarator_template_parameters): Likewise. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0ffa13de537..0e469259008 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2498,7 +2498,7 @@ static tree cp_parser_maybe_treat_template_as_class static bool cp_parser_check_declarator_template_parameters (cp_parser *, cp_declarator *, location_t); static bool cp_parser_check_template_parameters - (cp_parser *, unsigned, location_t, cp_declarator *); + (cp_parser *, unsigned, bool, location_t, cp_declarator *); static cp_expr cp_parser_simple_cast_expression (cp_parser *); static tree cp_parser_global_scope_opt @@ -17917,6 +17917,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, if (template_parm_lists_apply && !cp_parser_check_template_parameters (parser, /*num_templates=*/0, + /*template_id*/false, token->location, /*declarator=*/NULL)) return error_mark_node; @@ -18971,6 +18972,7 @@ cp_parser_alias_declaration (cp_parser* parser) if (parser->num_template_parameter_lists && !cp_parser_check_template_parameters (parser, /*num_templates=*/0, + /*template_id*/false, id_location, /*declarator=*/NULL)) return error_mark_node; @@ -23117,6 +23119,7 @@ cp_parser_class_head (cp_parser* parser, /* Make sure that the right number of template parameters were present. */ if (!cp_parser_check_template_parameters (parser, num_templates, + template_id_p, type_start_token->location, /*declarator=*/NULL)) { @@ -26391,17 +26394,22 @@ cp_parser_check_declarator_template_parameters (cp_parser* parser, { unsigned num_templates = 0; tree scope = declarator->u.id.qualifying_scope; + bool template_id_p = false; if (scope) num_templates = num_template_headers_for_class (scope); else if (TREE_CODE (declarator->u.id.unqualified_name) == TEMPLATE_ID_EXPR) - /* If the DECLARATOR has the form `X<y>' then it uses one - additional level of template parameters. */ - ++num_templates; + { + /* If the DECLARATOR has the form `X<y>' then it uses one + additional level of template parameters. */ + ++num_templates; + template_id_p = true; + } return cp_parser_check_template_parameters - (parser, num_templates, declarator_location, declarator); + (parser, num_templates, template_id_p, declarator_location, + declarator); } case cdk_function: @@ -26430,6 +26438,7 @@ cp_parser_check_declarator_template_parameters (cp_parser* parser, static bool cp_parser_check_template_parameters (cp_parser* parser, unsigned num_templates, + bool template_id_p, location_t location, cp_declarator *declarator) { @@ -26439,7 +26448,8 @@ cp_parser_check_template_parameters (cp_parser* parser, return true; /* If there are more, but only one more, then we are referring to a member template. That's OK too. */ - if (parser->num_template_parameter_lists == num_templates + 1) + if (!template_id_p + && parser->num_template_parameter_lists == num_templates + 1) return true; /* If there are more template classes than parameter lists, we have something like: diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic176.C b/gcc/testsuite/g++.dg/cpp0x/variadic176.C new file mode 100644 index 00000000000..1d6e3c2f10a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic176.C @@ -0,0 +1,10 @@ +// PR c++/85264 +// { dg-do compile { target c++11 } } + +template<typename> struct A {}; + +template<int> +template<typename... T> +struct A<void(T...)> {}; // { dg-error "too many template-parameter-lists" } + +A<void(int)> a;