[Clang] Support label at end of compound statement

Implements paper P2324R2
https://wg21.link/p2324r2
https://github.com/cplusplus/papers/issues/1006

Reviewed By: cor3ntin

Differential Revision: https://reviews.llvm.org/D133887
This commit is contained in:
Evgeny Shulgin 2022-09-14 18:08:34 +00:00
parent 133b6d7db9
commit 510383626f
9 changed files with 76 additions and 17 deletions

View File

@ -269,6 +269,9 @@ C2x Feature Support
so the [[maybe_unused]] attribute may be applied to a label to silence an
``-Wunused-label`` warning.
- Implemented `WG14 N508 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2508.pdf>`_,
so labels can placed everywhere inside a compound statement.
C++ Language Changes in Clang
-----------------------------
- Implemented DR692, DR1395 and DR1432. Use the ``-fclang-abi-compat=15`` option
@ -313,6 +316,8 @@ C++20 Feature Support
C++2b Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Support label at end of compound statement (`P2324 <https://wg21.link/p2324r2>`_).
CUDA/HIP Language Changes in Clang
----------------------------------

View File

@ -295,8 +295,20 @@ def note_missing_selector_name : Note<
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_c_label_end_of_compound_statement : ExtWarn<
"label at end of compound statement is a C2x extension">,
InGroup<C2x>;
def ext_cxx_label_end_of_compound_statement : ExtWarn<
"label at end of compound statement is a C++2b extension">,
InGroup<CXX2b>;
def warn_c2x_compat_label_end_of_compound_statement : Warning<
"label at end of compound statement is incompatible with C standards before C2x">,
InGroup<CPre2xCompat>, DefaultIgnore;
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<CXXPre2bCompat>, 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<

View File

@ -679,9 +679,12 @@ StmtResult Parser::ParseSEHLeaveStatement() {
/// 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,20 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
}
}
// The label may have no statement following it
if (SubStmt.isUnset() && Tok.is(tok::r_brace)) {
if (getLangOpts().CPlusPlus) {
Diag(Tok, getLangOpts().CPlusPlus2b
? diag::warn_cxx20_compat_label_end_of_compound_statement
: diag::ext_cxx_label_end_of_compound_statement);
} else {
Diag(Tok, getLangOpts().C2x
? diag::warn_c2x_compat_label_end_of_compound_statement
: diag::ext_c_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 +890,8 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
// 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 +945,8 @@ StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) {
// 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 +1113,10 @@ StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) {
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(),

View File

@ -161,6 +161,10 @@ label2:
// CHECK-NEXT: ImplicitCastExpr
// CHECK-NEXT: ImplicitCastExpr
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:9> 'void *' lvalue Var 0x{{[^ ]*}} 'ptr' 'void *'
label3:
// CHECK-NEXT: LabelStmt 0x{{[^ ]*}} <line:[[@LINE-1]]:1, col:7> 'label3'
// CHECK-NEXT: NullStmt 0x{{[^ ]*}} <col:7>
}
void TestSwitch(int i) {

View File

@ -0,0 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -std=c17 -Wc2x-compat -verify=c17 %s
// RUN: %clang_cc1 -fsyntax-only -std=c2x -Wpre-c2x-compat -verify=c2x %s
void foo() {
int x;
label1:
x = 1;
label2: label3: label4:
} // c17-warning {{label at end of compound statement is a C2x extension}} \
c2x-warning {{label at end of compound statement is incompatible with C standards before C2x}}

View File

@ -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}}

View File

@ -160,14 +160,14 @@ void test12(int x) {
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_1() {
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}}
}
}

View File

@ -763,7 +763,7 @@ conformance.</p>
<tr>
<td>Free positioning of labels inside compound statements</td>
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2508.pdf">N2508</a></td>
<td class="none" align="center">No</td>
<td class="unreleased" align="center">Clang 16</td>
</tr>
<tr>
<td>Clarification request for C17 example of undefined behavior</td>

View File

@ -1456,7 +1456,7 @@ C++20, informally referred to as C++2b.</p>
<tr>
<td>Labels at the end of compound statements</td>
<td><a href="https://wg21.link/P2324R2">P2324R2</a></td>
<td class="none" align="center">No</td>
<td class="unreleased" align="center">Clang 16</td>
</tr>
<tr>
<td>Delimited escape sequences</td>