diff options
author | Marek Polacek <polacek@redhat.com> | 2022-05-08 17:36:34 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2022-05-09 15:56:52 -0400 |
commit | 4b2a6628644b2ce15d877c1e85d14e314965a296 (patch) | |
tree | 93a5aedf0e767c9074643cee8c8e02a69cf1f689 | |
parent | 8c97f7fd2382aa77f36567207e949447db90a1fb (diff) | |
download | gcc-4b2a6628644b2ce15d877c1e85d14e314965a296.zip gcc-4b2a6628644b2ce15d877c1e85d14e314965a296.tar.gz gcc-4b2a6628644b2ce15d877c1e85d14e314965a296.tar.bz2 |
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.
-rw-r--r-- | gcc/cp/parser.cc | 43 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/label1.C | 89 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/label2.C | 52 |
3 files changed, 175 insertions, 9 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index a28e0e2..84b45cf 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -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: diff --git a/gcc/testsuite/g++.dg/cpp23/label1.C b/gcc/testsuite/g++.dg/cpp23/label1.C new file mode 100644 index 0000000..1465765 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/label1.C @@ -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 } } +} diff --git a/gcc/testsuite/g++.dg/cpp23/label2.C b/gcc/testsuite/g++.dg/cpp23/label2.C new file mode 100644 index 0000000..3457e71 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/label2.C @@ -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" } |