diff mbox

Fix PR c++/60065.

Message ID 1392865210-1632-1-git-send-email-adam@jessamine.co.uk
State New
Headers show

Commit Message

Adam Butcher Feb. 20, 2014, 3 a.m. UTC
PR c++/60065
        * parser.c (cp_parser_parameter_declaration_list): Use
        current_template_parms and scope check as predicate for
        inspecting current function template parameter list length
        rather than num_template_parameter_lists.

	PR c++/60065
	* g++.dg/cpp1y/pr60065.C: New testcase.
---
 gcc/cp/parser.c                      | 20 +++++++++++++++++---
 gcc/testsuite/g++.dg/cpp1y/pr60065.C |  8 ++++++++
 2 files changed, 25 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr60065.C

Comments

Jason Merrill Feb. 20, 2014, 4:18 p.m. UTC | #1
On 02/19/2014 10:00 PM, Adam Butcher wrote:
> +  if (current_template_parms)
> +    {
> +      cp_binding_level *maybe_tmpl_scope = current_binding_level->level_chain;
> +      while (maybe_tmpl_scope && maybe_tmpl_scope->kind == sk_class)
> +	maybe_tmpl_scope = maybe_tmpl_scope->level_chain;
> +      if (maybe_tmpl_scope && maybe_tmpl_scope->kind == sk_template_parms)
> +	declaring_template_p = true;
> +    }

Won't this return true for a member function of a class template?  i.e.

template <class T>
struct A {
   void f(auto x);
};

Why doesn't num_template_parameter_lists work as a predicate here?

Jason
Adam Butcher Feb. 21, 2014, 8:19 a.m. UTC | #2
On 2014-02-20 16:18, Jason Merrill wrote:
> On 02/19/2014 10:00 PM, Adam Butcher wrote:
>> +  if (current_template_parms)
>> +    {
>> +      cp_binding_level *maybe_tmpl_scope = 
>> current_binding_level->level_chain;
>> +      while (maybe_tmpl_scope && maybe_tmpl_scope->kind == 
>> sk_class)
>> +	maybe_tmpl_scope = maybe_tmpl_scope->level_chain;
>> +      if (maybe_tmpl_scope && maybe_tmpl_scope->kind == 
>> sk_template_parms)
>> +	declaring_template_p = true;
>> +    }
>
> Won't this return true for a member function of a class template?  
> i.e.
>
> template <class T>
> struct A {
>   void f(auto x);
> };
>
Yes I think you're right.  I was thinking about that yesterday but 
hadn't had a chance to get to my PC to check or post a reply.  The 
intent is to deal with out-of-line implicit member templates.  But I 
think the issue is more complex; and I think it may be true for the 
synthesize code as well as this new code.

A class template with an out-of-line generic function definition will 
give the same issue I think:

   template <typename T>
   void A<T>::f(auto x) {}  // should inject a new list

It needs to know when to extend a function template parameter list and 
when to insert a new one.  Another case:

   struct B
   {
     template <int N>
     void f(auto x);
   };

   template <int N>
   void B::f(auto x) {}  // should extend existing inner list

And also:

   template <typename T>
   struct C
   {
     template <int N>
     void f(auto x);
   };

   template <typename T>
   template <int N>
   void C<T>::f(auto x) {}  // should extend existing inner list

Obviously there is an arbitrary depth of class and class templates.

Need to look further into it when I get some more time.


Once it's resolved I think it'd be useful to create a new function to 
determine this rather than doing the scope walk in a number of places.  
Something like 'templ_parm_scope_for_fn_being_declared' --- or hopefully 
some more elegant name!


> Why doesn't num_template_parameter_lists work as a predicate here?
>
It works in the lambda case as it is updated there, but for generic 
functions I think the following prevents it:

   cp/parser.c:17063:

               /* Inside the function parameter list, surrounding
                  template-parameter-lists do not apply.  */
               saved_num_template_parameter_lists
                 = parser->num_template_parameter_lists;
               parser->num_template_parameter_lists = 0;

               begin_scope (sk_function_parms, NULL_TREE);

               /* Parse the parameter-declaration-clause.  */
               params = cp_parser_parameter_declaration_clause (parser);

               /* Restore saved template parameter lists accounting for 
implicit
                  template parameters.  */
               parser->num_template_parameter_lists
                 += saved_num_template_parameter_lists;


Cheers,
Adam
Jason Merrill Feb. 21, 2014, 3:49 p.m. UTC | #3
On 02/21/2014 03:19 AM, Adam Butcher wrote:
> A class template with an out-of-line generic function definition will
> give the same issue I think:
>
>    template <typename T>
>    void A<T>::f(auto x) {}  // should inject a new list

Right.  template_class_depth should be useful here.  This is basically 
the same question as whether a particular member function is a primary 
template (member template) or not, but figuring it out in the middle of 
the parameter list complicates things.

> Once it's resolved I think it'd be useful to create a new function to
> determine this rather than doing the scope walk in a number of places.
> Something like 'templ_parm_scope_for_fn_being_declared' --- or hopefully
> some more elegant name!

Right.

>> Why doesn't num_template_parameter_lists work as a predicate here?
>>
> It works in the lambda case as it is updated there, but for generic
> functions I think the following prevents it:
>
>    cp/parser.c:17063:
>
>                /* Inside the function parameter list, surrounding
>                   template-parameter-lists do not apply.  */
>                saved_num_template_parameter_lists
>                  = parser->num_template_parameter_lists;
>                parser->num_template_parameter_lists = 0;

Hmm, I wonder what that's for?  What breaks when you remove it? :)

Jason
Adam Butcher Feb. 23, 2014, 9:06 a.m. UTC | #4
On 2014-02-21 15:49, Jason Merrill wrote:
> On 02/21/2014 03:19 AM, Adam Butcher wrote:
>> Jason Merrill wrote:
>>> Why doesn't num_template_parameter_lists work as a predicate here?
>>>
>> It works in the lambda case as it is updated there, but for generic
>> functions I think the following prevents it:
>>
>>    cp/parser.c:17063:
>
> Hmm, I wonder what that's for?  What breaks when you remove it? :)
>
Nothing (according to the g++.dg testsuite at least).  It's been there 
since I started looking at GCC so I assumed that it was needed for 
something.  Having removed it I should be able use a 
num_template_parameter_lists and template_class_depth as you suggested 
to solve this issue (hopefully without the need of a scope walk).

Cheers,
Adam
diff mbox

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 68573f1..0b88bd3 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -18241,15 +18241,29 @@  cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
     = parser->in_unbraced_linkage_specification_p;
   parser->in_unbraced_linkage_specification_p = false;
 
+  /* Determine whether this parameter list applies to a function template
+     currently being declared to support extending the template with generic
+     type parameters.  */
+  bool declaring_template_p = false;
+  if (current_template_parms)
+    {
+      cp_binding_level *maybe_tmpl_scope = current_binding_level->level_chain;
+      while (maybe_tmpl_scope && maybe_tmpl_scope->kind == sk_class)
+	maybe_tmpl_scope = maybe_tmpl_scope->level_chain;
+      if (maybe_tmpl_scope && maybe_tmpl_scope->kind == sk_template_parms)
+	declaring_template_p = true;
+    }
+
   /* Look for more parameters.  */
   while (true)
     {
       cp_parameter_declarator *parameter;
       tree decl = error_mark_node;
       bool parenthesized_p = false;
-      int template_parm_idx = (parser->num_template_parameter_lists?
-			       TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
-						(current_template_parms)) : 0);
+      int template_parm_idx =
+	((declaring_template_p || parser->fully_implicit_function_template_p)?
+	 TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
+			  (current_template_parms)) : 0);
 
       /* Parse the parameter.  */
       parameter
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60065.C b/gcc/testsuite/g++.dg/cpp1y/pr60065.C
new file mode 100644
index 0000000..2aaa1e3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr60065.C
@@ -0,0 +1,8 @@ 
+// PR c++/60065
+// { dg-do compile }
+// { dg-options "-std=c++1y" }
+
+template <int> void foo(auto... x);
+template <typename> void foo2(auto... x);
+template <int> void foo3(auto... x, auto y, auto... z);
+template <typename> void foo4(auto... x, auto y, auto... z);