https://github.com/yronglin updated 
https://github.com/llvm/llvm-project/pull/146224

>From 43e2dc670d7c9ed5e23b5d26dff1e273c84b5a53 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin...@gmail.com>
Date: Thu, 3 Jul 2025 02:15:22 +0800
Subject: [PATCH 1/3] [C23][Parser] Diagnostic for attribute declaration where
 statement is required

Signed-off-by: yronglin <yronglin...@gmail.com>
---
 clang/docs/ReleaseNotes.rst                   |  4 ++
 .../clang/Basic/DiagnosticParseKinds.td       |  4 ++
 clang/include/clang/Parse/Parser.h            |  5 ++-
 clang/lib/Parse/ParseStmt.cpp                 | 40 ++++++++++++++-----
 clang/test/Parser/statements.c                | 30 ++++++++++++++
 clang/test/Sema/c2x-fallthrough.c             | 15 ++++---
 6 files changed, 82 insertions(+), 16 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3d893e0aa8e2c..60e7390c31e9b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -747,6 +747,10 @@ Bug Fixes in This Version
 - Fixed an infinite recursion when checking constexpr destructors. (#GH141789)
 - Fixed a crash when a malformed using declaration appears in a ``constexpr`` 
function. (#GH144264)
 - Fixed a bug when use unicode character name in macro concatenation. 
(#GH145240)
+- In C23, something like [[/*possible attributes*/]]; is an attribute 
declaration, not a statement. So it is not
+  allowed by the syntax in places where a statement is required, specifically 
as the secondary block of a
+  selection or iteration statement. This differs from C++, since C++ allows 
declaration statements. 
+  Clang now warning this patterns. (#GH141659)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 6c30da376dafb..9115b60cb0ed0 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -276,6 +276,10 @@ def err_expected_while : Error<"expected 'while' in 
do/while loop">;
 
 def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">;
 def err_expected_semi_after_expr : Error<"expected ';' after expression">;
+def warn_expected_stmt_before_semi_in_secondary_block : Warning<
+  "expected a statement before ';' but got an attribute declaration, "
+  "it is not allowed by the syntax in places where a statement is required">,
+  InGroup<CXXCompat>;
 def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">;
 
 def err_expected_semi_after_method_proto : Error<
diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index a47e23ffbd357..cca4f14a2942a 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -7168,13 +7168,16 @@ class Parser : public CodeCompletionHandler {
     AllowStandaloneOpenMPDirectives = 0x2,
     /// This context is at the top level of a GNU statement expression.
     InStmtExpr = 0x4,
+    /// This context is the C99 secondary-block in selection or iteration
+    /// statement.
+    SecondaryBlockInC = 0x8,
 
     /// The context of a regular substatement.
     SubStmt = 0,
     /// The context of a compound-statement.
     Compound = AllowDeclarationsInC | AllowStandaloneOpenMPDirectives,
 
-    LLVM_MARK_AS_BITMASK_ENUM(InStmtExpr)
+    LLVM_MARK_AS_BITMASK_ENUM(SecondaryBlockInC)
   };
 
   /// Act on an expression statement that might be the last statement in a
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 8217151a0259a..6080fb782dfbe 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -63,7 +63,8 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
   // at the start of the statement. Thus, we're not using MaybeParseAttributes
   // here because we don't want to allow arbitrary orderings.
   ParsedAttributes CXX11Attrs(AttrFactory);
-  MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true);
+  bool HasStdAttr =
+      MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true);
   ParsedAttributes GNUOrMSAttrs(AttrFactory);
   if (getLangOpts().OpenCL)
     MaybeParseGNUAttributes(GNUOrMSAttrs);
@@ -80,6 +81,12 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
   assert((CXX11Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
          "attributes on empty statement");
 
+  if (HasStdAttr && getLangOpts().C23 &&
+      (StmtCtx & ParsedStmtContext::SecondaryBlockInC) != ParsedStmtContext{} 
&&
+      isa_and_present<NullStmt>(Res.get()))
+    Diag(Res.get()->getBeginLoc(),
+         diag::warn_expected_stmt_before_semi_in_secondary_block);
+
   if (CXX11Attrs.empty() || Res.isInvalid())
     return Res;
 
@@ -1491,6 +1498,10 @@ StmtResult Parser::ParseIfStatement(SourceLocation 
*TrailingElseLoc) {
 
   SourceLocation InnerStatementTrailingElseLoc;
   StmtResult ThenStmt;
+  ParsedStmtContext StmtCtx = getLangOpts().C99
+                                  ? ParsedStmtContext::SecondaryBlockInC
+                                  : ParsedStmtContext::SubStmt;
+
   {
     bool ShouldEnter = ConstexprCondition && !*ConstexprCondition;
     Sema::ExpressionEvaluationContext Context =
@@ -1503,7 +1514,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation 
*TrailingElseLoc) {
     EnterExpressionEvaluationContext PotentiallyDiscarded(
         Actions, Context, nullptr,
         Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter);
-    ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc);
+    ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc, StmtCtx);
   }
 
   if (Tok.isNot(tok::kw_else))
@@ -1548,7 +1559,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation 
*TrailingElseLoc) {
     EnterExpressionEvaluationContext PotentiallyDiscarded(
         Actions, Context, nullptr,
         Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter);
-    ElseStmt = ParseStatement();
+    ElseStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
 
     if (ElseStmt.isUsable())
       MIChecker.Check();
@@ -1684,8 +1695,11 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation 
*TrailingElseLoc) {
   if (C99orCXX)
     getCurScope()->decrementMSManglingNumber();
 
+  ParsedStmtContext StmtCtx = getLangOpts().C99
+                                  ? ParsedStmtContext::SecondaryBlockInC
+                                  : ParsedStmtContext::SubStmt;
   // Read the body statement.
-  StmtResult Body(ParseStatement(TrailingElseLoc));
+  StmtResult Body(ParseStatement(TrailingElseLoc, StmtCtx));
 
   // Pop the scopes.
   InnerScope.Exit();
@@ -1754,9 +1768,11 @@ StmtResult Parser::ParseWhileStatement(SourceLocation 
*TrailingElseLoc) {
   ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, 
Tok.is(tok::l_brace));
 
   MisleadingIndentationChecker MIChecker(*this, MSK_while, WhileLoc);
-
+  ParsedStmtContext StmtCtx = getLangOpts().C99
+                                  ? ParsedStmtContext::SecondaryBlockInC
+                                  : ParsedStmtContext::SubStmt;
   // Read the body statement.
-  StmtResult Body(ParseStatement(TrailingElseLoc));
+  StmtResult Body(ParseStatement(TrailingElseLoc, StmtCtx));
 
   if (Body.isUsable())
     MIChecker.Check();
@@ -1799,9 +1815,11 @@ StmtResult Parser::ParseDoStatement() {
   //
   bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
   ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, 
Tok.is(tok::l_brace));
-
+  ParsedStmtContext StmtCtx = getLangOpts().C99
+                                  ? ParsedStmtContext::SecondaryBlockInC
+                                  : ParsedStmtContext::SubStmt;
   // Read the body statement.
-  StmtResult Body(ParseStatement());
+  StmtResult Body(ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx));
 
   // Pop the body scope if needed.
   InnerScope.Exit();
@@ -2221,9 +2239,11 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc) {
     getCurScope()->decrementMSManglingNumber();
 
   MisleadingIndentationChecker MIChecker(*this, MSK_for, ForLoc);
-
+  ParsedStmtContext StmtCtx = getLangOpts().C99
+                                  ? ParsedStmtContext::SecondaryBlockInC
+                                  : ParsedStmtContext::SubStmt;
   // Read the body statement.
-  StmtResult Body(ParseStatement(TrailingElseLoc));
+  StmtResult Body(ParseStatement(TrailingElseLoc, StmtCtx));
 
   if (Body.isUsable())
     MIChecker.Check();
diff --git a/clang/test/Parser/statements.c b/clang/test/Parser/statements.c
index 2566da83d7c53..ef331ac0448b0 100644
--- a/clang/test/Parser/statements.c
+++ b/clang/test/Parser/statements.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unreachable-code
+// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s -Wno-unreachable-code
 
 void test1(void) {
   { ; {  ;;}} ;;
@@ -77,3 +78,32 @@ int test9(void) {
 
   return 4, // expected-error {{expected ';' after return statement}}
 }
+
+#if __STDC_VERSION__ >= 202311L
+void attr_decl_in_selection_statement(int n) {
+  if (1)
+    [[]]; // expected-warning {{expected a statement before ';' but got an 
attribute declaration, it is not allowed by the syntax in places where a 
statement is required}}
+
+  if (1) {
+
+  } else
+    [[]]; // expected-warning {{expected a statement before ';' but got an 
attribute declaration, it is not allowed by the syntax in places where a 
statement is required}}
+
+
+  switch (n)
+    [[]]; // expected-warning {{expected a statement before ';' but got an 
attribute declaration, it is not allowed by the syntax in places where a 
statement is required}}
+}
+
+void attr_decl_in_iteration_statement(int n) {
+  int i;
+  for (i = 0; i < n; ++i)
+    [[]];     // expected-warning {{expected a statement before ';' but got an 
attribute declaration, it is not allowed by the syntax in places where a 
statement is required}}
+
+  while (i > 0)
+    [[]];     // expected-warning {{expected a statement before ';' but got an 
attribute declaration, it is not allowed by the syntax in places where a 
statement is required}}
+
+  do
+    [[]];     // expected-warning {{expected a statement before ';' but got an 
attribute declaration, it is not allowed by the syntax in places where a 
statement is required}}
+  while (i > 0);
+}
+#endif // __STDC_VERSION__ >= 202311L
diff --git a/clang/test/Sema/c2x-fallthrough.c 
b/clang/test/Sema/c2x-fallthrough.c
index 092d5285f80ba..d1d3b1e3727cc 100644
--- a/clang/test/Sema/c2x-fallthrough.c
+++ b/clang/test/Sema/c2x-fallthrough.c
@@ -16,17 +16,22 @@ void f(int n) {
     }
   case 2:
     for (int n = 0; n != 10; ++n)
-      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}}
+      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}} \
+                       // expected-warning {{expected a statement before ';' 
but got an attribute declaration, it is not allowed by the syntax in places 
where a statement is required}}
   case 3:
     while (1)
-      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}}
+      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}} \
+      // expected-warning {{expected a statement before ';' but got an 
attribute declaration, it is not allowed by the syntax in places where a 
statement is required}}
   case 4:
     while (0)
-      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}}
+      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}} \
+      // expected-warning {{expected a statement before ';' but got an 
attribute declaration, it is not allowed by the syntax in places where a 
statement is required}}
   case 5:
-    do [[fallthrough]]; while (1); // expected-error {{does not directly 
precede switch label}}
+    do [[fallthrough]]; while (1); // expected-error {{does not directly 
precede switch label}} \
+    // expected-warning {{expected a statement before ';' but got an attribute 
declaration, it is not allowed by the syntax in places where a statement is 
required}}
   case 6:
-    do [[fallthrough]]; while (0); // expected-error {{does not directly 
precede switch label}}
+    do [[fallthrough]]; while (0); // expected-error {{does not directly 
precede switch label}} \
+    // expected-warning {{expected a statement before ';' but got an attribute 
declaration, it is not allowed by the syntax in places where a statement is 
required}}
   case 7:
     switch (n) {
     case 0:

>From a4923f71671c8dd17395120a8c6efce40c61df7d Mon Sep 17 00:00:00 2001
From: yronglin <yronglin...@gmail.com>
Date: Thu, 3 Jul 2025 02:23:20 +0800
Subject: [PATCH 2/3] change c2x to c23

Signed-off-by: yronglin <yronglin...@gmail.com>
---
 clang/test/Sema/c2x-fallthrough.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/Sema/c2x-fallthrough.c 
b/clang/test/Sema/c2x-fallthrough.c
index d1d3b1e3727cc..e37cbb7e2c35b 100644
--- a/clang/test/Sema/c2x-fallthrough.c
+++ b/clang/test/Sema/c2x-fallthrough.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c2x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify %s
 
 // This is the latest version of fallthrough that we support.
 _Static_assert(__has_c_attribute(fallthrough) == 201910L);

>From a07b1a7d83572e54ffe754839e87493ce5b7447a Mon Sep 17 00:00:00 2001
From: yronglin <yronglin...@gmail.com>
Date: Mon, 7 Jul 2025 22:21:14 +0800
Subject: [PATCH 3/3] Update clang/docs/ReleaseNotes.rst

Co-authored-by: Mariya Podchishchaeva <mariya.podchishcha...@intel.com>
---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 60e7390c31e9b..5f907b800bef4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -750,7 +750,7 @@ Bug Fixes in This Version
 - In C23, something like [[/*possible attributes*/]]; is an attribute 
declaration, not a statement. So it is not
   allowed by the syntax in places where a statement is required, specifically 
as the secondary block of a
   selection or iteration statement. This differs from C++, since C++ allows 
declaration statements. 
-  Clang now warning this patterns. (#GH141659)
+  Clang now emits a warning for these patterns. (#GH141659)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to