diff mbox series

c++: generic lambda as default template argument [PR88313]

Message ID 20240729153802.1045105-1-ppalka@redhat.com
State New
Headers show
Series c++: generic lambda as default template argument [PR88313] | expand

Commit Message

Patrick Palka July 29, 2024, 3:38 p.m. UTC
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.

-- >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

Comments

Jason Merrill July 29, 2024, 7:29 p.m. UTC | #1
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 mbox series

Patch

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);