Author: yronglin
Date: 2025-07-09T08:54:30+08:00
New Revision: 191386fcd3335c5b7194da209d71d16549a2bb2f

URL: 
https://github.com/llvm/llvm-project/commit/191386fcd3335c5b7194da209d71d16549a2bb2f
DIFF: 
https://github.com/llvm/llvm-project/commit/191386fcd3335c5b7194da209d71d16549a2bb2f.diff

LOG: [C23][Parser] Diagnostic for attribute declaration where statement is 
required (#146224)

Fixes: https://github.com/llvm/llvm-project/issues/141659

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.

Therefore, code like the following should give a diagnostic (at least
with -std=c23 -pedantic), but Clang currently does not produce one:
```cpp
int main(void) {
    if (1)
        [[]];
}
```

---------

Signed-off-by: yronglin <yronglin...@gmail.com>
Signed-off-by: Wang, Yihan <yronglin...@gmail.com>
Co-authored-by: Mariya Podchishchaeva <mariya.podchishcha...@intel.com>

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/lib/Parse/ParseStmt.cpp
    clang/test/Parser/statements.c
    clang/test/Sema/c2x-fallthrough.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8b4f9229c4463..57a94242c9e61 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -767,6 +767,11 @@ Bug Fixes in This Version
   flag and diagnostic because the macro injection was used to emit this 
warning.
   Unfortunately there is no other good way to diagnose usage of 
``static_assert``
   macro without inclusion of ``<assert.h>``.
+- 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 
diff ers from C++, since C++ allows 
+  declaration statements. Clang now emits a warning for these patterns. 
(#GH141659)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 4636eaf2291ab..fd8e5c3c6ad87 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -276,6 +276,9 @@ 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_attr_in_secondary_block : ExtWarn<
+  "ISO C does not allow an attribute list to appear here">,
+  InGroup<DiagGroup<"c-attribute-extension">>;
 def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">;
 
 def err_expected_semi_after_method_proto : Error<

diff  --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 8217151a0259a..31b84b6f2ede0 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,13 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
   assert((CXX11Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
          "attributes on empty statement");
 
+  if (HasStdAttr && getLangOpts().C23 &&
+      (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) ==
+          ParsedStmtContext{} &&
+      isa_and_present<NullStmt>(Res.get()))
+    Diag(CXX11Attrs.Range.getBegin(), diag::warn_attr_in_secondary_block)
+        << CXX11Attrs.Range;
+
   if (CXX11Attrs.empty() || Res.isInvalid())
     return Res;
 

diff  --git a/clang/test/Parser/statements.c b/clang/test/Parser/statements.c
index 2566da83d7c53..22a6633bdf262 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 {{ISO C does not allow an attribute list to 
appear here}}
+
+  if (1) {
+
+  } else
+    [[]]; // expected-warning {{ISO C does not allow an attribute list to 
appear here}}
+
+
+  switch (n)
+    [[]]; // expected-warning {{ISO C does not allow an attribute list to 
appear here}}
+}
+
+void attr_decl_in_iteration_statement(int n) {
+  int i;
+  for (i = 0; i < n; ++i)
+    [[]];     // expected-warning {{ISO C does not allow an attribute list to 
appear here}}
+
+  while (i > 0)
+    [[]];     // expected-warning {{ISO C does not allow an attribute list to 
appear here}}
+
+  do
+    [[]];     // expected-warning {{ISO C does not allow an attribute list to 
appear here}}
+  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..7d2f25ed5187b 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);
@@ -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 {{ISO C does not allow an attribute 
list to appear here}}
   case 3:
     while (1)
-      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}}
+      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}} \
+      // expected-warning {{ISO C does not allow an attribute list to appear 
here}}
   case 4:
     while (0)
-      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}}
+      [[fallthrough]]; // expected-error {{does not directly precede switch 
label}} \
+      // expected-warning {{ISO C does not allow an attribute list to appear 
here}}
   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 {{ISO C does not allow an attribute list to appear 
here}}
   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 {{ISO C does not allow an attribute list to appear 
here}}
   case 7:
     switch (n) {
     case 0:


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

Reply via email to