From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1734) id A4EFD3948A4D; Mon, 9 May 2022 19:57:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A4EFD3948A4D MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Marek Polacek To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-217] c++: Implement P2324R2, labels at the end of compound-stmts [PR103539] X-Act-Checkin: gcc X-Git-Author: Marek Polacek X-Git-Refname: refs/heads/trunk X-Git-Oldrev: 8c97f7fd2382aa77f36567207e949447db90a1fb X-Git-Newrev: 4b2a6628644b2ce15d877c1e85d14e314965a296 Message-Id: <20220509195723.A4EFD3948A4D@sourceware.org> Date: Mon, 9 May 2022 19:57:23 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 09 May 2022 19:57:23 -0000 https://gcc.gnu.org/g:4b2a6628644b2ce15d877c1e85d14e314965a296 commit r13-217-g4b2a6628644b2ce15d877c1e85d14e314965a296 Author: Marek Polacek Date: Sun May 8 17:36:34 2022 -0400 c++: Implement P2324R2, labels at the end of compound-stmts [PR103539] This patch implements C++23 , 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. Diff: --- gcc/cp/parser.cc | 43 ++++++++++++++---- gcc/testsuite/g++.dg/cpp23/label1.C | 89 +++++++++++++++++++++++++++++++++++++ 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 a28e0e20c75..84b45cf47ec 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 *chain, + const bool in_compound, bool *if_p, vec *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 00000000000..14657652f4a --- /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 00000000000..3457e71ace2 --- /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" }