diff mbox series

c++: Implement P1102R2 - Down with ()!

Message ID 20210225184421.GL4020736@tucnak
State New
Headers show
Series c++: Implement P1102R2 - Down with ()! | expand

Commit Message

Jakub Jelinek Feb. 25, 2021, 6:44 p.m. UTC
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.


	Jakub

Comments

Jason Merrill Feb. 25, 2021, 9:22 p.m. UTC | #1
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
>
diff mbox series

Patch

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