c++: Implement P1102R2 - Down with ()!
authorJakub Jelinek <jakub@redhat.com>
Fri, 26 Feb 2021 09:44:52 +0000 (10:44 +0100)
committerJakub Jelinek <jakub@redhat.com>
Fri, 26 Feb 2021 09:47:07 +0000 (10:47 +0100)
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.

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

* parser.c (cp_parser_lambda_declarator_opt): Implement
P1102R2 - Down with ()! 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
gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C [new file with mode: 0644]

index 7077579..c52f90c 100644 (file)
@@ -11223,12 +11223,12 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
 /* 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_parser* parser, tree lambda_expr)
   tree tx_qual = NULL_TREE;
   tree return_type = NULL_TREE;
   tree trailing_requires_clause = NULL_TREE;
+  bool has_param_list = false;
+  location_t omitted_parms_loc = UNKNOWN_LOCATION;
   cp_decl_specifier_seq lambda_specs;
   clear_decl_specs (&lambda_specs);
   /* A lambda op() is const unless explicitly 'mutable'.  */
@@ -11334,42 +11336,80 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
                     "default argument specified for lambda parameter");
 
       parens.require_close (parser);
+      has_param_list = true;
+    }
+  else if (cxx_dialect < cxx23)
+    omitted_parms_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);
 
-      tx_qual = cp_parser_tx_qualifier_opt (parser);
+  if (omitted_parms_loc && lambda_specs.any_specifiers_p)
+    {
+      pedwarn (omitted_parms_loc, 0,
+              "parameter declaration before lambda declaration "
+              "specifiers only optional with %<-std=c++2b%> or "
+              "%<-std=gnu++2b%>");
+      omitted_parms_loc = UNKNOWN_LOCATION;
+    }
 
-      /* Parse optional exception specification.  */
-      exception_spec
-       = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
+  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%>");
+    }
 
-      std_attrs = cp_parser_std_attribute_spec_seq (parser);
+  tx_qual = cp_parser_tx_qualifier_opt (parser);
+  if (omitted_parms_loc && tx_qual)
+    {
+      pedwarn (omitted_parms_loc, 0,
+              "parameter declaration before lambda transaction "
+              "qualifier only optional with %<-std=c++2b%> or "
+              "%<-std=gnu++2b%>");
+      omitted_parms_loc = UNKNOWN_LOCATION;
+    }
 
-      /* 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 exception specification.  */
+  exception_spec
+    = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
 
-      if (cp_next_tokens_can_be_gnu_attribute_p (parser))
-       gnu_attrs = cp_parser_gnu_attributes_opt (parser);
+  if (omitted_parms_loc && exception_spec)
+    {
+      pedwarn (omitted_parms_loc, 0,
+              "parameter declaration before lambda exception "
+              "specification only optional with %<-std=c++2b%> or "
+              "%<-std=gnu++2b%>");
+      omitted_parms_loc = UNKNOWN_LOCATION;
+    }
 
+  std_attrs = cp_parser_std_attribute_spec_seq (parser);
+
+  /* Parse optional trailing return type.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
+    {
+      if (omitted_parms_loc)
+       pedwarn (omitted_parms_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 (has_param_list)
+    {
       /* Parse optional trailing requires clause.  */
       trailing_requires_clause = cp_parser_requires_clause_opt (parser, false);
 
diff --git a/gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C b/gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C
new file mode 100644 (file)
index 0000000..6729a45
--- /dev/null
@@ -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 } }
+}