diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -267,6 +267,8 @@ C++2b Feature Support ^^^^^^^^^^^^^^^^^^^^^ +- Support label at end of compound statement (`P2324 `_). + CUDA/HIP Language Changes in Clang ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -295,8 +295,14 @@ def note_force_empty_selector_name : Note< "or insert whitespace before ':' to use %0 as parameter name " "and have an empty entry in the selector">; -def err_label_end_of_compound_statement : Error< - "label at end of compound statement: expected statement">; +def err_switch_label_end_of_compound_statement : Error< + "label at end of switch compound statement: expected statement">; +def ext_label_end_of_compound_statement : ExtWarn< + "label at end of compound statement is a C++2b extension">, + InGroup; +def warn_cxx20_compat_label_end_of_compound_statement : Warning< + "label at end of compound statement is incompatible with C++ standards before C++2b">, + InGroup, DefaultIgnore; def err_address_of_label_outside_fn : Error< "use of address-of-label extension outside of a function body">; def err_asm_operand_wide_string_literal : Error< diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -679,9 +679,12 @@ /// ParseLabeledStatement - We have an identifier and a ':' after it. /// +/// label: +/// identifier ':' +/// [GNU] identifier ':' attributes[opt] +/// /// labeled-statement: -/// identifier ':' statement -/// [GNU] identifier ':' attributes[opt] statement +/// label statement /// StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs, ParsedStmtContext StmtCtx) { @@ -725,6 +728,14 @@ } } + // The label may have no statement following it + if (SubStmt.isUnset() && Tok.is(tok::r_brace)) { + Diag(Tok, getLangOpts().CPlusPlus2b + ? diag::warn_cxx20_compat_label_end_of_compound_statement + : diag::ext_label_end_of_compound_statement); + SubStmt = Actions.ActOnNullStmt(ColonLoc); + } + // If we've not parsed a statement yet, parse one now. if (!SubStmt.isInvalid() && !SubStmt.isUsable()) SubStmt = ParseStatement(nullptr, StmtCtx); @@ -873,8 +884,8 @@ // another parsing error, so avoid producing extra diagnostics. if (ColonLoc.isValid()) { SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); - Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) - << FixItHint::CreateInsertion(AfterColonLoc, " ;"); + Diag(AfterColonLoc, diag::err_switch_label_end_of_compound_statement) + << FixItHint::CreateInsertion(AfterColonLoc, " ;"); } SubStmt = StmtError(); } @@ -928,8 +939,8 @@ // Diagnose the common error "switch (X) {... default: }", which is // not valid. SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); - Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) - << FixItHint::CreateInsertion(AfterColonLoc, " ;"); + Diag(AfterColonLoc, diag::err_switch_label_end_of_compound_statement) + << FixItHint::CreateInsertion(AfterColonLoc, " ;"); SubStmt = true; } @@ -1096,10 +1107,10 @@ return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult); } -/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the -/// ActOnCompoundStmt action. This expects the '{' to be the current token, and -/// consume the '}' at the end of the block. It does not manipulate the scope -/// stack. +/// ParseCompoundStatementBody - Parse a sequence of statements optionally +/// followed by a label and invoke the ActOnCompoundStmt action. This expects +/// the '{' to be the current token, and consume the '}' at the end of the +/// block. It does not manipulate the scope stack. StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), Tok.getLocation(), diff --git a/clang/test/Parser/cxx2b-label.cpp b/clang/test/Parser/cxx2b-label.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Parser/cxx2b-label.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx2b -std=c++2b -Wpre-c++2b-compat %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s + +void foo() { +label1: + int x; +label2: + x = 1; +label3: label4: label5: +} // cxx20-warning {{label at end of compound statement is a C++2b extension}} \ + cxx2b-warning {{label at end of compound statement is incompatible with C++ standards before C++2b}} diff --git a/clang/test/Parser/switch-recovery.cpp b/clang/test/Parser/switch-recovery.cpp --- a/clang/test/Parser/switch-recovery.cpp +++ b/clang/test/Parser/switch-recovery.cpp @@ -160,14 +160,14 @@ void missing_statement_case(int x) { switch (x) { case 1: - case 0: // expected-error {{label at end of compound statement: expected statement}} + case 0: // expected-error {{label at end of switch compound statement: expected statement}} } } void missing_statement_default(int x) { switch (x) { case 0: - default: // expected-error {{label at end of compound statement: expected statement}} + default: // expected-error {{label at end of switch compound statement: expected statement}} } } @@ -179,7 +179,7 @@ void pr19022_1a(int x) { switch(x) { case 1 // expected-error{{expected ':' after 'case'}} \ - // expected-error{{label at end of compound statement: expected statement}} + // expected-error{{label at end of switch compound statement: expected statement}} } } diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -1456,7 +1456,7 @@ Labels at the end of compound statements P2324R2 - No + Clang 16 Delimited escape sequences