c++: P2360R0: Extend init-stmt to allow alias-decl [PR102617]

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.
This commit is contained in:
Marek Polacek 2021-10-21 11:10:02 -04:00
parent 2800628202
commit 5469d58d66
3 changed files with 95 additions and 31 deletions

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

View file

@ -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;
}
}

View file

@ -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" }
{
}
}