Author: Yanzuo Liu
Date: 2026-07-21T16:09:56+08:00
New Revision: d13b8625eef0941f48b5af74e9fab953b6430eb2

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

LOG: [clang][Parser] Warn when the body of expansion statement is not a 
compound statement (#209229)

<https://eel.is/c++draft/stmt.expand#nt:expansion-statement>:

_expansion-statement_:  
template for ( _init-statement<sub>opt</sub>_ _for-range-declaration_ :
_expansion-initializer_ ) _compound-statement_

Added: 
    clang/test/Parser/cxx2c-expansion-statements-non-compound-stmt-body.cpp

Modified: 
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/lib/Parse/ParseStmt.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 79583534b9bbd..b7072634cccf3 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -350,6 +350,7 @@ def ExtraTokens : DiagGroup<"extra-tokens">;
 def CXX98CompatExtraSemi : DiagGroup<"c++98-compat-extra-semi">;
 def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">;
 def EmptyInitStatement : DiagGroup<"empty-init-stmt">;
+def ExpansionStmtBody : DiagGroup<"expansion-stmt-missing-braces">;
 def ExportUnnamed : DiagGroup<"export-unnamed">;
 def ExtraSemiStmt : DiagGroup<"extra-semi-stmt", [EmptyInitStatement]>;
 def ExtraSemi : DiagGroup<"extra-semi", [CXX98CompatExtraSemi,

diff  --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index c411d89ef2fea..2672bfb2952c8 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -463,6 +463,12 @@ def err_expansion_stmt_requires_cxx2c : Error<
   "expansion statements are only supported in C++2c">;
 def err_for_template : Error<
   "'for template' is invalid; use 'template for' instead">;
+def ext_expansion_stmt_body_not_compound_stmt : Extension<
+  "ISO C++ requires the body of an expansion statement to be a compound 
statement">,
+  InGroup<ExpansionStmtBody>;
+def ext_expansion_stmt_body_attr : Extension<
+  "ISO C++ forbids attributes before the compound statement of an expansion 
statement">,
+  InGroup<ExpansionStmtBody>;
 
 def err_expected_case_before_expression: Error<
   "expected 'case' keyword before expression">;

diff  --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 973dbb803a42e..1d4bdf6d8f8e1 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2345,6 +2345,9 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
   // the other parts.
   getCurScope()->EnterLoopBody(PrecedingLabel);
 
+  bool BodyStartsWithAttr = Tok.isOneOf(tok::l_square, tok::kw___attribute);
+  SourceLocation BodyBeginLoc = Tok.getLocation();
+
   // C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
   // there is no compound stmt.  C90 does not have this clause.  We only do 
this
   // if the body isn't a compound statement to avoid push/pop in common cases.
@@ -2395,6 +2398,14 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
       return StmtError();
     }
 
+    // attribute-specifier without attribute (`[[]]`) isn't in AST.
+    // `__declspec()` is only applied to declarations, so we can ignore it.
+    if (!isa<CompoundStmt>(Body.get()) || BodyStartsWithAttr)
+      Diag(BodyBeginLoc,
+           isa<CompoundStmt>(Body.get()->stripLabelLikeStatements())
+               ? diag::ext_expansion_stmt_body_attr
+               : diag::ext_expansion_stmt_body_not_compound_stmt);
+
     return Actions.FinishCXXExpansionStmt(ForRangeStmt.get(), Body.get());
   }
 

diff  --git 
a/clang/test/Parser/cxx2c-expansion-statements-non-compound-stmt-body.cpp 
b/clang/test/Parser/cxx2c-expansion-statements-non-compound-stmt-body.cpp
new file mode 100644
index 0000000000000..5aae6a5305db8
--- /dev/null
+++ b/clang/test/Parser/cxx2c-expansion-statements-non-compound-stmt-body.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -Wexpansion-stmt-missing-braces 
-verify
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -Wpedantic -verify
+
+void f() {
+  template for (int x : {1})
+    template for (int y : {1}) // expected-warning {{ISO C++ requires the body 
of an expansion statement to be a compound statement}}
+      ; // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+  template for (int x : {1})
+    if (x) // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+      ;
+  template for (int x : {1})
+    switch (x) // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+      ;
+  template for (int x : {1})
+    for (;;) // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+      ;
+  template for (int x : {1})
+    while (x) // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+      ;
+  template for (int x : {1})
+    do // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+      ;
+    while (x);
+  template for (int x : {1})
+    return; // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+  template for (int x : {1})
+    [] {}(); // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+  template for (int x : {1})
+    [ // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+      []] if (x)
+      ;
+  template for (int x : {1})
+    [ // expected-warning {{ISO C++ requires the body of an expansion 
statement to be a compound statement}}
+      [likely]] if (x)
+      ;
+  template for (int x : {1})
+    [ // expected-warning {{ISO C++ forbids attributes before the compound 
statement of an expansion statement}}
+      []] {}
+  template for (int x : {1})
+    [ // expected-warning {{ISO C++ forbids attributes before the compound 
statement of an expansion statement}}
+      [likely]] {}
+  template for (int x : {1})
+    __attribute__ // expected-warning {{ISO C++ forbids attributes before the 
compound statement of an expansion statement}}
+      (()) {}
+  template for (int x : {1})
+    foo: {} // expected-error {{labels are not allowed in expansion 
statements}}
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to