public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: Implement P1102R2 - Down with ()!
@ 2021-02-25 18:44 Jakub Jelinek
  2021-02-25 21:22 ` Jason Merrill
  0 siblings, 1 reply; 2+ messages in thread
From: Jakub Jelinek @ 2021-02-25 18:44 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi!

The following patch implements P1102R2.
For attributes, we have already attribute parsing before the parameter
declarations and so when that is omitted, if the attributes are first we
already accept it.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Or defer for GCC 12?

2021-02-25  Jakub Jelinek  <jakub@redhat.com>

	P1102R2 - Down with ()!
	* parser.c (cp_parser_lambda_declarator_opt): Make ()s
	optional before lambda specifiers for -std={c,gnu}++2b or
	with pedwarn in earlier versions.

	* g++.dg/cpp23/lambda-specifiers1.C: New test.

--- gcc/cp/parser.c.jj	2021-02-12 09:58:25.341506456 +0100
+++ gcc/cp/parser.c	2021-02-25 14:28:37.525431561 +0100
@@ -11223,12 +11223,12 @@ cp_parser_lambda_introducer (cp_parser*
 /* Parse the (optional) middle of a lambda expression.
 
    lambda-declarator:
-     ( parameter-declaration-clause )
-       decl-specifier-seq [opt]
-       noexcept-specifier [opt]
-       attribute-specifier-seq [opt]
-       trailing-return-type [opt]
-       requires-clause [opt]
+     ( parameter-declaration-clause ) lambda-specifiers requires-clause [opt]
+     lambda-specifiers (C++23)
+
+   lambda-specifiers:
+     decl-specifier-seq [opt] noexcept-specifier [opt]
+       attribute-specifier-seq [opt] trailing-return-type [opt]
 
    LAMBDA_EXPR is the current representation of the lambda expression.  */
 
@@ -11248,6 +11248,8 @@ cp_parser_lambda_declarator_opt (cp_pars
   tree tx_qual = NULL_TREE;
   tree return_type = NULL_TREE;
   tree trailing_requires_clause = NULL_TREE;
+  bool has_param_list = false;
+  location_t lambda_specifiers_loc = UNKNOWN_LOCATION;
   cp_decl_specifier_seq lambda_specs;
   clear_decl_specs (&lambda_specs);
   /* A lambda op() is const unless explicitly 'mutable'.  */
@@ -11334,47 +11336,88 @@ cp_parser_lambda_declarator_opt (cp_pars
 		     "default argument specified for lambda parameter");
 
       parens.require_close (parser);
+      has_param_list = true;
+    }
+  else if (cxx_dialect < cxx23)
+    lambda_specifiers_loc = cp_lexer_peek_token (parser->lexer)->location;
 
-      /* In the decl-specifier-seq of the lambda-declarator, each
-	 decl-specifier shall either be mutable or constexpr.  */
-      int declares_class_or_enum;
-      if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
-	  && !cp_next_tokens_can_be_gnu_attribute_p (parser))
-	cp_parser_decl_specifier_seq (parser,
-				      CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
-				      &lambda_specs, &declares_class_or_enum);
-      if (lambda_specs.storage_class == sc_mutable)
-	{
-	  LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
-	  quals = TYPE_UNQUALIFIED;
-	  if (lambda_specs.conflicting_specifiers_p)
-	    error_at (lambda_specs.locations[ds_storage_class],
-		      "duplicate %<mutable%>");
-	}
+  /* In the decl-specifier-seq of the lambda-declarator, each
+     decl-specifier shall either be mutable or constexpr.  */
+  int declares_class_or_enum;
+  if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
+      && !cp_next_tokens_can_be_gnu_attribute_p (parser))
+    cp_parser_decl_specifier_seq (parser,
+				  CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
+				  &lambda_specs, &declares_class_or_enum);
+
+  if (lambda_specifiers_loc
+      && (lambda_specs.storage_class == sc_mutable
+	  || lambda_specs.locations[ds_constexpr]
+	  || lambda_specs.locations[ds_consteval]))
+    {
+      pedwarn (lambda_specifiers_loc, 0,
+	       "parameter declaration before lambda declaration "
+	       "specifiers only optional with %<-std=c++2b%> or "
+	       "%<-std=gnu++2b%>");
+      lambda_specifiers_loc = UNKNOWN_LOCATION;
+    }
+
+  if (lambda_specs.storage_class == sc_mutable)
+    {
+      LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
+      quals = TYPE_UNQUALIFIED;
+      if (lambda_specs.conflicting_specifiers_p)
+	error_at (lambda_specs.locations[ds_storage_class],
+		  "duplicate %<mutable%>");
+    }
+
+  tx_qual = cp_parser_tx_qualifier_opt (parser);
+  if (lambda_specifiers_loc && tx_qual)
+    {
+      pedwarn (lambda_specifiers_loc, 0,
+	       "parameter declaration before lambda transaction "
+	       "qualifier only optional with %<-std=c++2b%> or "
+	       "%<-std=gnu++2b%>");
+      lambda_specifiers_loc = UNKNOWN_LOCATION;
+    }
+
+  /* Parse optional exception specification.  */
+  exception_spec
+    = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
+
+  if (lambda_specifiers_loc && exception_spec)
+    {
+      pedwarn (lambda_specifiers_loc, 0,
+	       "parameter declaration before lambda exception "
+	       "specification only optional with %<-std=c++2b%> or "
+	       "%<-std=gnu++2b%>");
+      lambda_specifiers_loc = UNKNOWN_LOCATION;
+    }
 
-      tx_qual = cp_parser_tx_qualifier_opt (parser);
+  std_attrs = cp_parser_std_attribute_spec_seq (parser);
 
-      /* Parse optional exception specification.  */
-      exception_spec
-	= cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
-
-      std_attrs = cp_parser_std_attribute_spec_seq (parser);
-
-      /* Parse optional trailing return type.  */
-      if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
-        {
-          cp_lexer_consume_token (parser->lexer);
-          return_type = cp_parser_trailing_type_id (parser);
-        }
+  /* Parse optional trailing return type.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
+    {
+      if (lambda_specifiers_loc)
+	pedwarn (lambda_specifiers_loc, 0,
+		 "parameter declaration before lambda trailing "
+		 "return type only optional with %<-std=c++2b%> or "
+		 "%<-std=gnu++2b%>");
+      cp_lexer_consume_token (parser->lexer);
+      return_type = cp_parser_trailing_type_id (parser);
+    }
 
-      if (cp_next_tokens_can_be_gnu_attribute_p (parser))
-	gnu_attrs = cp_parser_gnu_attributes_opt (parser);
+  if (cp_next_tokens_can_be_gnu_attribute_p (parser))
+    gnu_attrs = cp_parser_gnu_attributes_opt (parser);
 
+  if (has_param_list)
+    {
       /* Parse optional trailing requires clause.  */
       trailing_requires_clause = cp_parser_requires_clause_opt (parser, false);
 
-      /* The function parameters must be in scope all the way until after the
-         trailing-return-type in case of decltype.  */
+      /* The function parameters must be in scope all the way until after
+	 the trailing-return-type in case of decltype.  */
       pop_bindings_and_leave_scope ();
     }
 
--- gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C.jj	2021-02-25 14:55:14.719567663 +0100
+++ gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C	2021-02-25 15:00:36.608082855 +0100
@@ -0,0 +1,18 @@
+// P1102R2 - Down with ()!
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+void
+foo ()
+{
+  auto a = [] mutable {};	// { dg-warning "parameter declaration before lambda declaration specifiers only optional with" "" { target c++20_down } }
+#if __cpp_constexpr >= 201603L
+  auto b = [] constexpr {};	// { dg-warning "parameter declaration before lambda declaration specifiers only optional with" "" { target { c++17 && c++20_down } } }
+#endif
+#if __cpp_consteval >= 201811L
+  auto c = [] consteval {};	// { dg-warning "parameter declaration before lambda declaration specifiers only optional with" "" { target c++20_only } }
+#endif
+  auto d = [] throw() {};	// { dg-warning "parameter declaration before lambda exception specification only optional with" "" { target c++20_down } }
+  auto e = [] noexcept {};	// { dg-warning "parameter declaration before lambda exception specification only optional with" "" { target c++20_down } }
+  auto f = [] -> int { return 0; };	// { dg-warning "parameter declaration before lambda trailing return type only optional with" "" { target c++20_down } }
+}

	Jakub


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] c++: Implement P1102R2 - Down with ()!
  2021-02-25 18:44 [PATCH] c++: Implement P1102R2 - Down with ()! Jakub Jelinek
@ 2021-02-25 21:22 ` Jason Merrill
  0 siblings, 0 replies; 2+ messages in thread
From: Jason Merrill @ 2021-02-25 21:22 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 2/25/21 1:44 PM, Jakub Jelinek wrote:
> Hi!
> 
> The following patch implements P1102R2.
> For attributes, we have already attribute parsing before the parameter
> declarations and so when that is omitted, if the attributes are first we
> already accept it.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> Or defer for GCC 12?
> 
> 2021-02-25  Jakub Jelinek  <jakub@redhat.com>
> 
> 	P1102R2 - Down with ()!
> 	* parser.c (cp_parser_lambda_declarator_opt): Make ()s
> 	optional before lambda specifiers for -std={c,gnu}++2b or
> 	with pedwarn in earlier versions.
> 
> 	* g++.dg/cpp23/lambda-specifiers1.C: New test.
> 
> --- gcc/cp/parser.c.jj	2021-02-12 09:58:25.341506456 +0100
> +++ gcc/cp/parser.c	2021-02-25 14:28:37.525431561 +0100
> @@ -11223,12 +11223,12 @@ cp_parser_lambda_introducer (cp_parser*
>   /* Parse the (optional) middle of a lambda expression.
>   
>      lambda-declarator:
> -     ( parameter-declaration-clause )
> -       decl-specifier-seq [opt]
> -       noexcept-specifier [opt]
> -       attribute-specifier-seq [opt]
> -       trailing-return-type [opt]
> -       requires-clause [opt]
> +     ( parameter-declaration-clause ) lambda-specifiers requires-clause [opt]
> +     lambda-specifiers (C++23)
> +
> +   lambda-specifiers:
> +     decl-specifier-seq [opt] noexcept-specifier [opt]
> +       attribute-specifier-seq [opt] trailing-return-type [opt]
>   
>      LAMBDA_EXPR is the current representation of the lambda expression.  */
>   
> @@ -11248,6 +11248,8 @@ cp_parser_lambda_declarator_opt (cp_pars
>     tree tx_qual = NULL_TREE;
>     tree return_type = NULL_TREE;
>     tree trailing_requires_clause = NULL_TREE;
> +  bool has_param_list = false;
> +  location_t lambda_specifiers_loc = UNKNOWN_LOCATION;

Let's call this omitted_parms_loc, since that's what it's used for.

>     cp_decl_specifier_seq lambda_specs;
>     clear_decl_specs (&lambda_specs);
>     /* A lambda op() is const unless explicitly 'mutable'.  */
> @@ -11334,47 +11336,88 @@ cp_parser_lambda_declarator_opt (cp_pars
>   		     "default argument specified for lambda parameter");
>   
>         parens.require_close (parser);
> +      has_param_list = true;
> +    }
> +  else if (cxx_dialect < cxx23)
> +    lambda_specifiers_loc = cp_lexer_peek_token (parser->lexer)->location;
>   
> -      /* In the decl-specifier-seq of the lambda-declarator, each
> -	 decl-specifier shall either be mutable or constexpr.  */
> -      int declares_class_or_enum;
> -      if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
> -	  && !cp_next_tokens_can_be_gnu_attribute_p (parser))
> -	cp_parser_decl_specifier_seq (parser,
> -				      CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
> -				      &lambda_specs, &declares_class_or_enum);
> -      if (lambda_specs.storage_class == sc_mutable)
> -	{
> -	  LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
> -	  quals = TYPE_UNQUALIFIED;
> -	  if (lambda_specs.conflicting_specifiers_p)
> -	    error_at (lambda_specs.locations[ds_storage_class],
> -		      "duplicate %<mutable%>");
> -	}
> +  /* In the decl-specifier-seq of the lambda-declarator, each
> +     decl-specifier shall either be mutable or constexpr.  */
> +  int declares_class_or_enum;
> +  if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
> +      && !cp_next_tokens_can_be_gnu_attribute_p (parser))
> +    cp_parser_decl_specifier_seq (parser,
> +				  CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
> +				  &lambda_specs, &declares_class_or_enum);
> +
> +  if (lambda_specifiers_loc
> +      && (lambda_specs.storage_class == sc_mutable
> +	  || lambda_specs.locations[ds_constexpr]
> +	  || lambda_specs.locations[ds_consteval]))

Maybe lambda_specs.any_specifiers_p instead of checking them individually?

> +    {
> +      pedwarn (lambda_specifiers_loc, 0,
> +	       "parameter declaration before lambda declaration "
> +	       "specifiers only optional with %<-std=c++2b%> or "
> +	       "%<-std=gnu++2b%>");
> +      lambda_specifiers_loc = UNKNOWN_LOCATION;
> +    }
> +
> +  if (lambda_specs.storage_class == sc_mutable)
> +    {
> +      LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
> +      quals = TYPE_UNQUALIFIED;
> +      if (lambda_specs.conflicting_specifiers_p)
> +	error_at (lambda_specs.locations[ds_storage_class],
> +		  "duplicate %<mutable%>");
> +    }
> +
> +  tx_qual = cp_parser_tx_qualifier_opt (parser);
> +  if (lambda_specifiers_loc && tx_qual)
> +    {
> +      pedwarn (lambda_specifiers_loc, 0,
> +	       "parameter declaration before lambda transaction "
> +	       "qualifier only optional with %<-std=c++2b%> or "
> +	       "%<-std=gnu++2b%>");
> +      lambda_specifiers_loc = UNKNOWN_LOCATION;
> +    }
> +
> +  /* Parse optional exception specification.  */
> +  exception_spec
> +    = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
> +
> +  if (lambda_specifiers_loc && exception_spec)
> +    {
> +      pedwarn (lambda_specifiers_loc, 0,
> +	       "parameter declaration before lambda exception "
> +	       "specification only optional with %<-std=c++2b%> or "
> +	       "%<-std=gnu++2b%>");
> +      lambda_specifiers_loc = UNKNOWN_LOCATION;
> +    }
>   
> -      tx_qual = cp_parser_tx_qualifier_opt (parser);
> +  std_attrs = cp_parser_std_attribute_spec_seq (parser);
>   
> -      /* Parse optional exception specification.  */
> -      exception_spec
> -	= cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
> -
> -      std_attrs = cp_parser_std_attribute_spec_seq (parser);
> -
> -      /* Parse optional trailing return type.  */
> -      if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
> -        {
> -          cp_lexer_consume_token (parser->lexer);
> -          return_type = cp_parser_trailing_type_id (parser);
> -        }
> +  /* Parse optional trailing return type.  */
> +  if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
> +    {
> +      if (lambda_specifiers_loc)
> +	pedwarn (lambda_specifiers_loc, 0,
> +		 "parameter declaration before lambda trailing "
> +		 "return type only optional with %<-std=c++2b%> or "
> +		 "%<-std=gnu++2b%>");
> +      cp_lexer_consume_token (parser->lexer);
> +      return_type = cp_parser_trailing_type_id (parser);
> +    }
>   
> -      if (cp_next_tokens_can_be_gnu_attribute_p (parser))
> -	gnu_attrs = cp_parser_gnu_attributes_opt (parser);
> +  if (cp_next_tokens_can_be_gnu_attribute_p (parser))
> +    gnu_attrs = cp_parser_gnu_attributes_opt (parser);
>   
> +  if (has_param_list)
> +    {
>         /* Parse optional trailing requires clause.  */
>         trailing_requires_clause = cp_parser_requires_clause_opt (parser, false);
>   
> -      /* The function parameters must be in scope all the way until after the
> -         trailing-return-type in case of decltype.  */
> +      /* The function parameters must be in scope all the way until after
> +	 the trailing-return-type in case of decltype.  */

This rewrapping seems unnecessary.

OK for trunk with those changes, this seems safe enough.

>         pop_bindings_and_leave_scope ();
>       }
>   
> --- gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C.jj	2021-02-25 14:55:14.719567663 +0100
> +++ gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C	2021-02-25 15:00:36.608082855 +0100
> @@ -0,0 +1,18 @@
> +// P1102R2 - Down with ()!
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +
> +void
> +foo ()
> +{
> +  auto a = [] mutable {};	// { dg-warning "parameter declaration before lambda declaration specifiers only optional with" "" { target c++20_down } }
> +#if __cpp_constexpr >= 201603L
> +  auto b = [] constexpr {};	// { dg-warning "parameter declaration before lambda declaration specifiers only optional with" "" { target { c++17 && c++20_down } } }
> +#endif
> +#if __cpp_consteval >= 201811L
> +  auto c = [] consteval {};	// { dg-warning "parameter declaration before lambda declaration specifiers only optional with" "" { target c++20_only } }
> +#endif
> +  auto d = [] throw() {};	// { dg-warning "parameter declaration before lambda exception specification only optional with" "" { target c++20_down } }
> +  auto e = [] noexcept {};	// { dg-warning "parameter declaration before lambda exception specification only optional with" "" { target c++20_down } }
> +  auto f = [] -> int { return 0; };	// { dg-warning "parameter declaration before lambda trailing return type only optional with" "" { target c++20_down } }
> +}
> 
> 	Jakub
> 


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-02-25 21:22 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-25 18:44 [PATCH] c++: Implement P1102R2 - Down with ()! Jakub Jelinek
2021-02-25 21:22 ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).