]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: P2360R0: Extend init-stmt to allow alias-decl [PR102617]
authorMarek Polacek <polacek@redhat.com>
Thu, 21 Oct 2021 15:10:02 +0000 (11:10 -0400)
committerMarek Polacek <polacek@redhat.com>
Tue, 26 Oct 2021 15:34:53 +0000 (11:34 -0400)
The following patch implements C++23 P2360R0.  This proposal merely
extends init-statement to contain alias-declaration.  init-statement
is used in if/for/switch.  It also removes the unsightly duplication
of code by calling cp_parser_init_statement twice.

PR c++/102617

gcc/cp/ChangeLog:

* parser.c (cp_parser_for): Maybe call cp_parser_init_statement
twice.  Warn about range-based for loops with initializer here.
(cp_parser_init_statement): Don't duplicate code.  Allow
alias-declaration in init-statement.

gcc/testsuite/ChangeLog:

* g++.dg/cpp23/init-stmt1.C: New test.
* g++.dg/cpp23/init-stmt2.C: New test.

gcc/cp/parser.c
gcc/testsuite/g++.dg/cpp23/init-stmt1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/init-stmt2.C [new file with mode: 0644]

index 49d951cfb193ce18079460eda1e9a4be045cf487..93335c817d7eb451dffe32b3e18329eecbcec646 100644 (file)
@@ -12040,6 +12040,7 @@ cp_parser_handle_directive_omp_attributes (cp_parser *parser, tree *pattrs,
   init-statement:
     expression-statement
     simple-declaration
+    alias-declaration
 
   TM Extension:
 
@@ -13327,6 +13328,23 @@ cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll)
   /* Begin the for-statement.  */
   scope = begin_for_scope (&init);
 
+  /* Maybe parse the optional init-statement in a range-based for loop.  */
+  if (cp_parser_range_based_for_with_init_p (parser)
+      /* Checked for diagnostic purposes only.  */
+      && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+    {
+      tree dummy;
+      cp_parser_init_statement (parser, &dummy);
+      if (cxx_dialect < cxx20)
+       {
+         pedwarn (cp_lexer_peek_token (parser->lexer)->location,
+                  OPT_Wc__20_extensions,
+                  "range-based %<for%> loops with initializer only "
+                  "available with %<-std=c++20%> or %<-std=gnu++20%>");
+         decl = error_mark_node;
+       }
+    }
+
   /* Parse the initialization.  */
   is_range_for = cp_parser_init_statement (parser, &decl);
 
@@ -13987,12 +14005,13 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep,
   return statement;
 }
 
-/* Parse a init-statement or the declarator of a range-based-for.
+/* Parse an init-statement or the declarator of a range-based-for.
    Returns true if a range-based-for declaration is seen.
 
    init-statement:
      expression-statement
-     simple-declaration  */
+     simple-declaration
+     alias-declaration  */
 
 static bool
 cp_parser_init_statement (cp_parser *parser, tree *decl)
@@ -14008,40 +14027,29 @@ cp_parser_init_statement (cp_parser *parser, tree *decl)
       bool is_range_for = false;
       bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
 
-      /* Try to parse the init-statement.  */
-      if (cp_parser_range_based_for_with_init_p (parser))
-       {
-         tree dummy;
-         cp_parser_parse_tentatively (parser);
-         /* Parse the declaration.  */
-         cp_parser_simple_declaration (parser,
-                                       /*function_definition_allowed_p=*/false,
-                                       &dummy);
-         cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
-         if (!cp_parser_parse_definitely (parser))
-           /* That didn't work, try to parse it as an expression-statement.  */
-           cp_parser_expression_statement (parser, NULL_TREE);
-
-         if (cxx_dialect < cxx20)
-           {
-             pedwarn (cp_lexer_peek_token (parser->lexer)->location,
-                      OPT_Wc__20_extensions,
-                      "range-based %<for%> loops with initializer only "
-                      "available with %<-std=c++20%> or %<-std=gnu++20%>");
-             *decl = error_mark_node;
-           }
-       }
-
       /* A colon is used in range-based for.  */
       parser->colon_corrects_to_scope_p = false;
 
       /* We're going to speculatively look for a declaration, falling back
         to an expression, if necessary.  */
       cp_parser_parse_tentatively (parser);
-      /* Parse the declaration.  */
-      cp_parser_simple_declaration (parser,
-                                   /*function_definition_allowed_p=*/false,
-                                   decl);
+      bool expect_semicolon_p = true;
+      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
+       {
+         cp_parser_alias_declaration (parser);
+         expect_semicolon_p = false;
+         if (cxx_dialect < cxx23
+             && !cp_parser_uncommitted_to_tentative_parse_p (parser))
+           pedwarn (cp_lexer_peek_token (parser->lexer)->location,
+                    OPT_Wc__23_extensions,
+                    "alias-declaration in init-statement only "
+                    "available with %<-std=c++23%> or %<-std=gnu++23%>");
+       }
+      else
+       /* Parse the declaration.  */
+       cp_parser_simple_declaration (parser,
+                                     /*function_definition_allowed_p=*/false,
+                                     decl);
       parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
       if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
        {
@@ -14054,7 +14062,7 @@ cp_parser_init_statement (cp_parser *parser, tree *decl)
                     "range-based %<for%> loops only available with "
                     "%<-std=c++11%> or %<-std=gnu++11%>");
        }
-      else
+      else if (expect_semicolon_p)
        /* The ';' is not consumed yet because we told
           cp_parser_simple_declaration not to.  */
        cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
diff --git a/gcc/testsuite/g++.dg/cpp23/init-stmt1.C b/gcc/testsuite/g++.dg/cpp23/init-stmt1.C
new file mode 100644 (file)
index 0000000..29e3256
--- /dev/null
@@ -0,0 +1,31 @@
+// PR c++/102617
+// P2360R0: Extend init-statement to allow alias-declaration
+// { dg-do compile { target c++20 } }
+// Test valid use.
+
+int v[10];
+
+void
+g ()
+{
+  for (using T = int; (T) false;) // { dg-error "only available with" "" { target c++20_only } }
+    ;
+  for (using T = int; T e : v) // { dg-error "only available with" "" { target c++20_only } }
+    (void) e;
+  if (using T = int; true) // { dg-error "only available with" "" { target c++20_only } }
+    {
+      T x = 0;
+      (void) x;
+    }
+  if constexpr (using T = int; true) // { dg-error "only available with" "" { target c++20_only } }
+    {
+      T x = 0;
+      (void) x;
+    }
+  switch (using T = int; 42) // { dg-error "only available with" "" { target c++20_only } }
+    case 42:
+      {
+       T x = 0;
+       (void) x;
+      }
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/init-stmt2.C b/gcc/testsuite/g++.dg/cpp23/init-stmt2.C
new file mode 100644 (file)
index 0000000..ca6201b
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/102617
+// P2360R0: Extend init-statement to allow alias-declaration
+// { dg-do compile { target c++23 } }
+// Test invalid use.
+
+int v[10];
+namespace N { using X = int; }
+
+void
+g ()
+{
+  for (using N::X; false;) // { dg-error "expected" }
+    ;
+  for (using N::X; int e : v) // { dg-error "expected" }
+    (void) e;
+  for (using T = int; using U = int; int e : v) // { dg-error "" }
+    ;
+  if (using N::X; false) // { dg-error "expected" }
+    {}
+  switch (using N::X; 0) // { dg-error "expected" }
+    ;
+ if (using T = int;) // { dg-error "expected" }
+  {
+  }
+}