c++: Implement P2324R2, labels at the end of compound-stmts [PR103539]
This patch implements C++23 <https://wg21.link/p2324r2>, which allows labels at the end of a compound statement. Its C FE counterpart was already implemented in r11-4813. In cp_parser_statement I rely on in_compound to determine whether we're in a compound-statement, so that the patch doesn't accidentally allow void fn(int c) { if (c) label: } Strangely, in_compound was reset after seeing a label (this is tested in c-c++-common/gomp/pr63326.c), so I've made a modifiable copy specific for OpenMP #pragma purposes. PR c++/103539 gcc/cp/ChangeLog: * parser.cc (cp_parser_statement): Constify the in_compound parameter. Create a modifiable copy. Allow labels at the end of compound statements. gcc/testsuite/ChangeLog: * g++.dg/cpp23/label1.C: New test. * g++.dg/cpp23/label2.C: New test.
This commit is contained in:
parent
8c97f7fd23
commit
4b2a662864
3 changed files with 175 additions and 9 deletions
|
@ -12174,7 +12174,7 @@ cp_parser_handle_directive_omp_attributes (cp_parser *parser, tree *pattrs,
|
|||
atomic-statement
|
||||
|
||||
IN_COMPOUND is true when the statement is nested inside a
|
||||
cp_parser_compound_statement; this matters for certain pragmas.
|
||||
cp_parser_compound_statement.
|
||||
|
||||
If IF_P is not NULL, *IF_P is set to indicate whether the statement
|
||||
is a (possibly labeled) if statement which is not enclosed in braces
|
||||
|
@ -12184,7 +12184,7 @@ cp_parser_handle_directive_omp_attributes (cp_parser *parser, tree *pattrs,
|
|||
|
||||
static void
|
||||
cp_parser_statement (cp_parser* parser, tree in_statement_expr,
|
||||
bool in_compound, bool *if_p, vec<tree> *chain,
|
||||
const bool in_compound, bool *if_p, vec<tree> *chain,
|
||||
location_t *loc_after_labels)
|
||||
{
|
||||
tree statement, std_attrs = NULL_TREE;
|
||||
|
@ -12192,6 +12192,9 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
|
|||
location_t statement_location, attrs_loc;
|
||||
bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
|
||||
bool has_std_attrs;
|
||||
/* A copy of IN_COMPOUND which is set to false after seeing a label.
|
||||
This matters for certain pragmas. */
|
||||
bool in_compound_for_pragma = in_compound;
|
||||
|
||||
restart:
|
||||
if (if_p != NULL)
|
||||
|
@ -12286,7 +12289,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
|
|||
Parse the label, and then use tail recursion to parse
|
||||
the statement. */
|
||||
cp_parser_label_for_labeled_statement (parser, std_attrs);
|
||||
in_compound = false;
|
||||
in_compound_for_pragma = false;
|
||||
in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
|
||||
goto restart;
|
||||
|
||||
|
@ -12370,7 +12373,21 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
|
|||
the statement. */
|
||||
|
||||
cp_parser_label_for_labeled_statement (parser, std_attrs);
|
||||
in_compound = false;
|
||||
|
||||
/* If there's no statement, it's not a labeled-statement, just
|
||||
a label. That's allowed in C++23, but only if we're at the
|
||||
end of a compound-statement. */
|
||||
if (in_compound
|
||||
&& cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
|
||||
{
|
||||
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
|
||||
if (cxx_dialect < cxx23)
|
||||
pedwarn (loc, OPT_Wc__23_extensions,
|
||||
"label at end of compound statement only available "
|
||||
"with %<-std=c++2b%> or %<-std=gnu++2b%>");
|
||||
return;
|
||||
}
|
||||
in_compound_for_pragma = false;
|
||||
in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
|
||||
goto restart;
|
||||
}
|
||||
|
@ -12393,7 +12410,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
|
|||
the context of a compound, accept the pragma as a "statement" and
|
||||
return so that we can check for a close brace. Otherwise we
|
||||
require a real statement and must go back and read one. */
|
||||
if (in_compound)
|
||||
if (in_compound_for_pragma)
|
||||
cp_parser_pragma (parser, pragma_compound, if_p);
|
||||
else if (!cp_parser_pragma (parser, pragma_stmt, if_p))
|
||||
do_restart = true;
|
||||
|
@ -12544,9 +12561,13 @@ attr_chainon (tree attrs, tree attr)
|
|||
|
||||
/* Parse the label for a labeled-statement, i.e.
|
||||
|
||||
identifier :
|
||||
case constant-expression :
|
||||
default :
|
||||
label:
|
||||
attribute-specifier-seq[opt] identifier :
|
||||
attribute-specifier-seq[opt] case constant-expression :
|
||||
attribute-specifier-seq[opt] default :
|
||||
|
||||
labeled-statement:
|
||||
label statement
|
||||
|
||||
GNU Extension:
|
||||
case constant-expression ... constant-expression : statement
|
||||
|
@ -12766,7 +12787,11 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
|
|||
/* Parse a compound-statement.
|
||||
|
||||
compound-statement:
|
||||
{ statement-seq [opt] }
|
||||
{ statement-seq [opt] label-seq [opt] }
|
||||
|
||||
label-seq:
|
||||
label
|
||||
label-seq label
|
||||
|
||||
GNU extension:
|
||||
|
||||
|
|
89
gcc/testsuite/g++.dg/cpp23/label1.C
Normal file
89
gcc/testsuite/g++.dg/cpp23/label1.C
Normal file
|
@ -0,0 +1,89 @@
|
|||
// P2324R2 - Labels at the end of compound statements
|
||||
// PR c++/103539
|
||||
// { dg-do compile }
|
||||
// Test good cases.
|
||||
|
||||
void
|
||||
p2324 ()
|
||||
{
|
||||
first:
|
||||
int x;
|
||||
second:
|
||||
x = 1;
|
||||
last:
|
||||
} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
|
||||
|
||||
void
|
||||
fn1 ()
|
||||
{
|
||||
l1:
|
||||
} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
|
||||
|
||||
void
|
||||
fn2 ()
|
||||
{
|
||||
if (1)
|
||||
{
|
||||
l1:
|
||||
} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
|
||||
}
|
||||
|
||||
void
|
||||
fn3 ()
|
||||
{
|
||||
{
|
||||
{
|
||||
label:
|
||||
} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fn4 ()
|
||||
{
|
||||
switch (1)
|
||||
{
|
||||
lab:
|
||||
} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
|
||||
}
|
||||
|
||||
void
|
||||
fn5 ()
|
||||
{
|
||||
l1:
|
||||
l2:
|
||||
l3:
|
||||
} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
|
||||
|
||||
void
|
||||
fn6 ()
|
||||
{
|
||||
;
|
||||
l1:
|
||||
l2:
|
||||
l3:
|
||||
} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
|
||||
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
void
|
||||
fn7 ()
|
||||
{
|
||||
auto l = [](){
|
||||
lab:
|
||||
}; // { dg-error "label at end of compound statement only available with" "" { target { c++20_down && c++11 } } }
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
fn8 ()
|
||||
{
|
||||
try
|
||||
{
|
||||
lab1:
|
||||
} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
|
||||
catch (int)
|
||||
{
|
||||
lab2:
|
||||
} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
|
||||
}
|
52
gcc/testsuite/g++.dg/cpp23/label2.C
Normal file
52
gcc/testsuite/g++.dg/cpp23/label2.C
Normal file
|
@ -0,0 +1,52 @@
|
|||
// P2324R2 - Labels at the end of compound statements
|
||||
// PR c++/103539
|
||||
// { dg-do compile { target c++23 } }
|
||||
// Test bad cases.
|
||||
|
||||
void
|
||||
fn1 ()
|
||||
{
|
||||
/* A selection-statement wants a statement, but a mere label isn't a statement. */
|
||||
if (1)
|
||||
lab:
|
||||
} // { dg-error "expected" }
|
||||
|
||||
void
|
||||
fn2 ()
|
||||
{
|
||||
if (0)
|
||||
{
|
||||
}
|
||||
else
|
||||
lab:
|
||||
} // { dg-error "expected" }
|
||||
|
||||
void
|
||||
fn3 ()
|
||||
{
|
||||
do
|
||||
lab:
|
||||
while (0); // { dg-error "expected" }
|
||||
} // { dg-error "expected" }
|
||||
|
||||
void
|
||||
fn4 ()
|
||||
{
|
||||
for (;;)
|
||||
lab:
|
||||
} // { dg-error "expected" }
|
||||
|
||||
void
|
||||
fn5 ()
|
||||
{
|
||||
switch (1)
|
||||
lab:
|
||||
} // { dg-error "expected" }
|
||||
|
||||
void
|
||||
fn6 ()
|
||||
{
|
||||
if (1)
|
||||
lab1:
|
||||
lab2:
|
||||
} // { dg-error "expected" }
|
Loading…
Add table
Reference in a new issue