[clang] 5103836 - [Clang] Support label at end of compound statement

Evgeny Shulgin via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 17 08:35:20 PDT 2022


Author: Evgeny Shulgin
Date: 2022-09-17T15:34:56Z
New Revision: 510383626fe146e49ae5fa036638e543ce71e5d9

URL: https://github.com/llvm/llvm-project/commit/510383626fe146e49ae5fa036638e543ce71e5d9
DIFF: https://github.com/llvm/llvm-project/commit/510383626fe146e49ae5fa036638e543ce71e5d9.diff

LOG: [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

Added: 
    clang/test/Parser/c2x-label.c
    clang/test/Parser/cxx2b-label.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/lib/Parse/ParseStmt.cpp
    clang/test/AST/ast-dump-stmt.c
    clang/test/Parser/switch-recovery.cpp
    clang/www/c_status.html
    clang/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 240228a6d5e7..403d50b1c9d4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -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
 ----------------------------------
 

diff  --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 84504b15764b..0293c2c03b52 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -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<

diff  --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index d785c393fef9..1a3363604a33 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -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(),

diff  --git a/clang/test/AST/ast-dump-stmt.c b/clang/test/AST/ast-dump-stmt.c
index 12fa4b15daaf..ba0c38ab1880 100644
--- a/clang/test/AST/ast-dump-stmt.c
+++ b/clang/test/AST/ast-dump-stmt.c
@@ -161,6 +161,10 @@ void TestLabelsAndGoto(void) {
   // 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) {

diff  --git a/clang/test/Parser/c2x-label.c b/clang/test/Parser/c2x-label.c
new file mode 100644
index 000000000000..6141e5bcb76d
--- /dev/null
+++ b/clang/test/Parser/c2x-label.c
@@ -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}}

diff  --git a/clang/test/Parser/cxx2b-label.cpp b/clang/test/Parser/cxx2b-label.cpp
new file mode 100644
index 000000000000..99b42b5d5631
--- /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
index eacd017ab236..ba83355c7928 100644
--- a/clang/test/Parser/switch-recovery.cpp
+++ b/clang/test/Parser/switch-recovery.cpp
@@ -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}}
   }
 }
 

diff  --git a/clang/www/c_status.html b/clang/www/c_status.html
index c9d33b4e94b4..395bdf5d22da 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -763,7 +763,7 @@ <h2 id="c2x">C2x implementation status</h2>
     <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>

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index e9a71bba7a0b..06ad3868dd9d 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1456,7 +1456,7 @@ <h2 id="cxx23">C++2b implementation status</h2>
     <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>


        


More information about the cfe-commits mailing list