diff mbox series

C++ PATCH for c++/85264, ICE with extra template parameter list

Message ID CADzB+2m4o-ADUwUh3bgQ8yvQnLVxUkRRmP8u9QB5h6JBZFRm2Q@mail.gmail.com
State New
Headers show
Series C++ PATCH for c++/85264, ICE with extra template parameter list | expand

Commit Message

Jason Merrill April 9, 2018, 7:39 p.m. UTC
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.

Comments

Paolo Carlini April 9, 2018, 10:55 p.m. UTC | #1
Hi,

On 09/04/2018 21:39, Jason Merrill wrote:
> 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.
Nice, it looks like this also fixes the prehistoric c++/24314, which I 
still had assigned. When I worked a bit on it, relatively recently, in 
2012, I failed to properly follow-up to your feedback on the mailing 
list, but I don't think we really nailed the problem, did we?

     https://gcc.gnu.org/ml/gcc-patches/2012-09/msg00504.html

Or maybe we just tried to do too much, like doing away completely with 
cp_parser_check_template_parameters in favor of a bit of additional 
checking in maybe_process_partial_specialization.

Paolo.
Jason Merrill April 10, 2018, 1:50 p.m. UTC | #2
On Mon, Apr 9, 2018 at 6:55 PM, Paolo Carlini <paolo.carlini@oracle.com> wrote:
> On 09/04/2018 21:39, Jason Merrill wrote:
>>
>> 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.
>
> Nice, it looks like this also fixes the prehistoric c++/24314, which I still
> had assigned.

Great!

> When I worked a bit on it, relatively recently, in 2012, I
> failed to properly follow-up to your feedback on the mailing list, but I
> don't think we really nailed the problem, did we?
>
>     https://gcc.gnu.org/ml/gcc-patches/2012-09/msg00504.html
>
> Or maybe we just tried to do too much, like doing away completely with
> cp_parser_check_template_parameters in favor of a bit of additional checking
> in maybe_process_partial_specialization.

I'm sure late checking like we discussed there can also work, but this
ended up being a simple way to make the current code work better...

Jason
Jason Merrill April 10, 2018, 1:52 p.m. UTC | #3
On Tue, Apr 10, 2018 at 9:50 AM, Jason Merrill <jason@redhat.com> wrote:
> On Mon, Apr 9, 2018 at 6:55 PM, Paolo Carlini <paolo.carlini@oracle.com> wrote:
>> On 09/04/2018 21:39, Jason Merrill wrote:
>>>
>>> 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.
>>
>> Nice, it looks like this also fixes the prehistoric c++/24314, which I still
>> had assigned.
>
> Great!
>
>> When I worked a bit on it, relatively recently, in 2012, I
>> failed to properly follow-up to your feedback on the mailing list, but I
>> don't think we really nailed the problem, did we?
>>
>>     https://gcc.gnu.org/ml/gcc-patches/2012-09/msg00504.html
>>
>> Or maybe we just tried to do too much, like doing away completely with
>> cp_parser_check_template_parameters in favor of a bit of additional checking
>> in maybe_process_partial_specialization.
>
> I'm sure late checking like we discussed there can also work, but this
> ended up being a simple way to make the current code work better...

But as discussed in that thread, we should still improve the comment:
commit 2072134d123d64535baac00ea4bb6ffbce045caf
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Apr 10 09:42:54 2018 -0400

            * parser.c (cp_parser_check_template_parameters): Improve comment.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d4b62c75c44..849a75a1a51 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -26452,8 +26452,8 @@ cp_parser_check_template_parameters (cp_parser* parser,
      lists, that's OK.  */
   if (parser->num_template_parameter_lists == num_templates)
     return true;
-  /* If there are more, but only one more, then we are referring to a
-     member template.  That's OK too.  */
+  /* If there are more, but only one more, and the name ends in an identifier,
+     then we are declaring a primary template.  That's OK too.  */
   if (!template_id_p
       && parser->num_template_parameter_lists == num_templates + 1)
     return true;
diff mbox series

Patch

commit 770f6eaf7320d908cd39ace3aa155e7ec829982d
Author: Jason Merrill <jason@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;