https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127782
Bug ID: 127782
Summary: [C++20] Empty init-statement in range-for (`for (;
decl : range-init)`) is incorrectly rejected
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: rejects-valid
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: gabravier at gmail dot com
Target Milestone: ---
int a[1];
void f() { for (; int x : a); }
My reading of [stmt.ranged]/[stmt.pre] is that this is a valid range-based for
with an empty init-statement (from expression-statement -> `expression(opt)
;`). Clang agrees. GCC does not:
<source>: In function 'void f()':
<source>:2:25: error: found ':' in nested-name-specifier, expected '::'
2 | void f() { for (; int x : a); }
| ^
| ::
<source>:2:23: error: 'x' has not been declared
2 | void f() { for (; int x : a); }
| ^
<source>:2:28: error: qualified-id in declaration before ')' token
2 | void f() { for (; int x : a); }
| ^
<source>:2:28: error: expected ';' before ')' token
2 | void f() { for (; int x : a); }
| ^
| ;
This function seems to think it should be able to parse it:
/* Parses a for-statement or range-for-statement until the closing ')',
not included. */
static tree
cp_parser_for (cp_parser *parser, bool ivdep, tree unroll, bool novector)
{
tree init, scope, decl;
bool is_range_for;
/* 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);
if (is_range_for)
return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll,
novector, false);
else
return cp_parser_c_for (parser, scope, init, ivdep, unroll, novector);
}
...but the "for diagnostics purpose only" cp_lexer_next_token_is_not certainly
seems to do more to the code's behaviour than mere diagnostics x) (I believe if
it were simply removed this would just fix this, although I have not tested it)
P.S: the following
void f() {
template for (; auto x : {1, 2, 3}) { (void)x; }
}
also has the same issue, I believe for the exact same reason (an identical
conditional) in cp_parser_expansion_statement.