Message ID | 1392865210-1632-1-git-send-email-adam@jessamine.co.uk |
---|---|
State | New |
Headers | show |
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
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
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
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 --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);