Message ID | 20240729153802.1045105-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: generic lambda as default template argument [PR88313] | expand |
On 7/29/24 11:38 AM, Patrick Palka wrote: > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this > look OK for trunk and perhaps 14.3? It should only make a differenc > for C++20 code where lambdas are permitted as template arguments. OK for both. > -- >8 -- > > Here we're rejecting the generic lambda inside the default template > argument ultimately because auto_is_implicit_function_template_parm_p > doesn't get set during parsing of the lambda's parameter list, due > to the !processing_template_parmlist restriction. But when parsing a > lambda parameter list we should always set that flag regardless of where > the lambda appears. This patch makes sure this happens by way of a > local lambda_p flag. > > PR c++/88313 > > gcc/cp/ChangeLog: > > * parser.cc (cp_parser_lambda_declarator_opt): Pass > lambda_p=true to cp_parser_parameter_declaration_clause. > (cp_parser_direct_declarator): Pass lambda_p=false to > to cp_parser_parameter_declaration_clause. > (cp_parser_parameter_declaration_clause): Add bool lambda_p > parameter. Consider lambda_p instead of current_class_type > when setting parser->auto_is_implicit_function_template_parm_p. > Don't consider processing_template_parmlist. > (cp_parser_requirement_parameter_list): Pass lambda_p=false > to cp_parser_parameter_declaration_clause. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/lambda-targ6.C: New test. > --- > gcc/cp/parser.cc | 34 +++++++++++++---------- > gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C | 11 ++++++++ > 2 files changed, 31 insertions(+), 14 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index f79736c17ac..f5336eae74a 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -2600,7 +2600,7 @@ static tree cp_parser_type_id_1 > static void cp_parser_type_specifier_seq > (cp_parser *, cp_parser_flags, bool, bool, cp_decl_specifier_seq *); > static tree cp_parser_parameter_declaration_clause > - (cp_parser *, cp_parser_flags); > + (cp_parser *, cp_parser_flags, bool); > static tree cp_parser_parameter_declaration_list > (cp_parser *, cp_parser_flags, auto_vec<tree> *); > static cp_parameter_declarator *cp_parser_parameter_declaration > @@ -11889,7 +11889,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) > /* Parse parameters. */ > param_list > = cp_parser_parameter_declaration_clause > - (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL); > + (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, /*lambda_p=*/true); > > /* Default arguments shall not be specified in the > parameter-declaration-clause of a lambda-declarator. */ > @@ -24097,7 +24097,8 @@ cp_parser_direct_declarator (cp_parser* parser, > > /* Parse the parameter-declaration-clause. */ > params > - = cp_parser_parameter_declaration_clause (parser, flags); > + = cp_parser_parameter_declaration_clause (parser, flags, > + /*lambda=*/false); > const location_t parens_end > = cp_lexer_peek_token (parser->lexer)->location; > > @@ -25444,13 +25445,17 @@ function_being_declared_is_template_p (cp_parser* parser) > > The parser flags FLAGS is used to control type-specifier parsing. > > + LAMBDA_P is true if this is the parameter-declaration-clause of > + a lambda-declarator. > + > Returns a representation for the parameter declarations. A return > value of NULL indicates a parameter-declaration-clause consisting > only of an ellipsis. */ > > static tree > cp_parser_parameter_declaration_clause (cp_parser* parser, > - cp_parser_flags flags) > + cp_parser_flags flags, > + bool lambda_p) > { > tree parameters; > cp_token *token; > @@ -25459,15 +25464,15 @@ cp_parser_parameter_declaration_clause (cp_parser* parser, > auto cleanup = make_temp_override > (parser->auto_is_implicit_function_template_parm_p); > > - if (!processing_specialization > - && !processing_template_parmlist > - && !processing_explicit_instantiation > - /* default_arg_ok_p tracks whether this is a parameter-clause for an > - actual function or a random abstract declarator. */ > - && parser->default_arg_ok_p) > - if (!current_function_decl > - || (current_class_type && LAMBDA_TYPE_P (current_class_type))) > - parser->auto_is_implicit_function_template_parm_p = true; > + if (lambda_p > + || (!processing_specialization > + && !processing_template_parmlist > + && !processing_explicit_instantiation > + /* default_arg_ok_p tracks whether this is a parameter-clause for an > + actual function or a random abstract declarator. */ > + && parser->default_arg_ok_p > + && !current_function_decl)) > + parser->auto_is_implicit_function_template_parm_p = true; > > /* Peek at the next token. */ > token = cp_lexer_peek_token (parser->lexer); > @@ -31743,7 +31748,8 @@ cp_parser_requirement_parameter_list (cp_parser *parser) > return error_mark_node; > > tree parms = (cp_parser_parameter_declaration_clause > - (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL)); > + (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, > + /*lambda_p=*/false)); > > if (!parens.require_close (parser)) > return error_mark_node; > diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C > new file mode 100644 > index 00000000000..6dbcbf40970 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C > @@ -0,0 +1,11 @@ > +// PR c++/88313 > +// { dg-do compile { target c++20 } } > + > +template<int N = [](auto x) { return x; }(42)> > +constexpr int f() { return N; } > + > +template<class T = decltype([](auto x) { return x; })> > +constexpr int g(T t = {}) { return t(42); } > + > +static_assert(f() == 42); > +static_assert(g() == 42);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index f79736c17ac..f5336eae74a 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2600,7 +2600,7 @@ static tree cp_parser_type_id_1 static void cp_parser_type_specifier_seq (cp_parser *, cp_parser_flags, bool, bool, cp_decl_specifier_seq *); static tree cp_parser_parameter_declaration_clause - (cp_parser *, cp_parser_flags); + (cp_parser *, cp_parser_flags, bool); static tree cp_parser_parameter_declaration_list (cp_parser *, cp_parser_flags, auto_vec<tree> *); static cp_parameter_declarator *cp_parser_parameter_declaration @@ -11889,7 +11889,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) /* Parse parameters. */ param_list = cp_parser_parameter_declaration_clause - (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL); + (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, /*lambda_p=*/true); /* Default arguments shall not be specified in the parameter-declaration-clause of a lambda-declarator. */ @@ -24097,7 +24097,8 @@ cp_parser_direct_declarator (cp_parser* parser, /* Parse the parameter-declaration-clause. */ params - = cp_parser_parameter_declaration_clause (parser, flags); + = cp_parser_parameter_declaration_clause (parser, flags, + /*lambda=*/false); const location_t parens_end = cp_lexer_peek_token (parser->lexer)->location; @@ -25444,13 +25445,17 @@ function_being_declared_is_template_p (cp_parser* parser) The parser flags FLAGS is used to control type-specifier parsing. + LAMBDA_P is true if this is the parameter-declaration-clause of + a lambda-declarator. + Returns a representation for the parameter declarations. A return value of NULL indicates a parameter-declaration-clause consisting only of an ellipsis. */ static tree cp_parser_parameter_declaration_clause (cp_parser* parser, - cp_parser_flags flags) + cp_parser_flags flags, + bool lambda_p) { tree parameters; cp_token *token; @@ -25459,15 +25464,15 @@ cp_parser_parameter_declaration_clause (cp_parser* parser, auto cleanup = make_temp_override (parser->auto_is_implicit_function_template_parm_p); - if (!processing_specialization - && !processing_template_parmlist - && !processing_explicit_instantiation - /* default_arg_ok_p tracks whether this is a parameter-clause for an - actual function or a random abstract declarator. */ - && parser->default_arg_ok_p) - if (!current_function_decl - || (current_class_type && LAMBDA_TYPE_P (current_class_type))) - parser->auto_is_implicit_function_template_parm_p = true; + if (lambda_p + || (!processing_specialization + && !processing_template_parmlist + && !processing_explicit_instantiation + /* default_arg_ok_p tracks whether this is a parameter-clause for an + actual function or a random abstract declarator. */ + && parser->default_arg_ok_p + && !current_function_decl)) + parser->auto_is_implicit_function_template_parm_p = true; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -31743,7 +31748,8 @@ cp_parser_requirement_parameter_list (cp_parser *parser) return error_mark_node; tree parms = (cp_parser_parameter_declaration_clause - (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL)); + (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, + /*lambda_p=*/false)); if (!parens.require_close (parser)) return error_mark_node; diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C new file mode 100644 index 00000000000..6dbcbf40970 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ6.C @@ -0,0 +1,11 @@ +// PR c++/88313 +// { dg-do compile { target c++20 } } + +template<int N = [](auto x) { return x; }(42)> +constexpr int f() { return N; } + +template<class T = decltype([](auto x) { return x; })> +constexpr int g(T t = {}) { return t(42); } + +static_assert(f() == 42); +static_assert(g() == 42);