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;

Reply via email to