https://github.com/zwuis updated 
https://github.com/llvm/llvm-project/pull/209229

>From 6858ff8a03b5f20eb262b2a404974079a9b33c4f Mon Sep 17 00:00:00 2001
From: Yanzuo Liu <[email protected]>
Date: Mon, 13 Jul 2026 23:57:51 +0800
Subject: [PATCH 1/3] Warn when the body of expansion statement is not a
 compound statement

---
 .../clang/Basic/DiagnosticParseKinds.td       |   3 +
 clang/lib/Parse/ParseStmt.cpp                 |   9 +-
 .../Parser/cxx2c-expansion-statements.cpp     | 115 +++++++++++++-----
 3 files changed, 96 insertions(+), 31 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 55b26deed0750..389900040399a 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -457,6 +457,9 @@ 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_requires_braced_body : ExtWarn<
+  "ISO C++ requires a compound statement to be the body of expansion 
statement">,
+  InGroup<DiagGroup<"expansion-stmt-braced-body">>, DefaultIgnore;
 
 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 bdaea72cf52a1..bbde87794b652 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2329,6 +2329,10 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
   // the other parts.
   getCurScope()->EnterLoopBody(PrecedingLabel);
 
+  bool BodyIsCompoundStmt = Tok.is(tok::l_brace);
+  // attribute-specifier without attribute (`[[]]`) isn't in AST.
+  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.
@@ -2341,7 +2345,7 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
   // for-init-statement/condition and a new scope for substatement in C++.
   //
   ParseScope InnerScope(this, Scope::DeclScope, C99orCXXorObjC,
-                        Tok.is(tok::l_brace));
+                        BodyIsCompoundStmt);
 
   // The body of the for loop has the same local mangling number as the
   // for-init-statement.
@@ -2379,6 +2383,9 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
       return StmtError();
     }
 
+    if (!BodyIsCompoundStmt)
+      Diag(BodyBeginLoc, diag::ext_expansion_stmt_requires_braced_body);
+
     return Actions.FinishCXXExpansionStmt(ForRangeStmt.get(), Body.get());
   }
 
diff --git a/clang/test/Parser/cxx2c-expansion-statements.cpp 
b/clang/test/Parser/cxx2c-expansion-statements.cpp
index 736f9fead383c..2ca94270cd60a 100644
--- a/clang/test/Parser/cxx2c-expansion-statements.cpp
+++ b/clang/test/Parser/cxx2c-expansion-statements.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -verify
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -verify=expected,brace 
-Wexpansion-stmt-braced-body
 namespace std {
 template <typename T>
 struct initializer_list {
@@ -14,31 +15,82 @@ void bad() {
   template for (;); // expected-error {{expected ';' in 'for' statement 
specifier}} expected-error {{expansion statement must use the syntax of a 
range-based for loop}}
   template for (;;); // expected-error {{expansion statement must use the 
syntax of a range-based for loop}}
   template for (int x;;); // expected-error {{expansion statement must use the 
syntax of a range-based for loop}}
-  template for (x : {1}); // expected-error {{expansion statement requires 
type for expansion variable}}
+  template for (x : {1});
+  // expected-error@-1 {{expansion statement requires type for expansion 
variable}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
   template for (: {1}); // expected-error {{expected expression}} 
expected-error {{expected ';' in 'for' statement specifier}} expected-error 
{{expansion statement must use the syntax of a range-based for loop}}
   template for (auto y : {1})]; // expected-error {{expected expression}}
-  template for (auto y : {1}; // expected-error {{expected ')'}} expected-note 
{{to match this '('}}
-  template for (extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}}
-  template for (register auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'register'}} expected-error {{ISO C++17 does 
not allow 'register' storage class specifier}}
-  template for (__private_extern__ auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'extern'}}
-  template for (extern static auto y : {1, 2}); // expected-error {{cannot 
combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}}
-  template for (static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}}
-  template for (thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}}
-  template for (static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}}
-  template for (__thread auto y : {1, 2}); // expected-error {{'__thread' 
variables must have global storage}}
-  template for (static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}}
-  template for (constinit auto y : {1, 2}); // expected-error {{local variable 
cannot be declared 'constinit'}}
-  template for (consteval auto y : {1, 2});  // expected-error {{consteval can 
only be used in function declarations}}
-  template for (int x; extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}}
-  template for (int x; extern static auto y : {1, 2}); // expected-error 
{{cannot combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}}
-  template for (int x; static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}}
-  template for (int x; thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}}
-  template for (int x; static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}}
-  template for (int x; __thread auto y : {1, 2}); // expected-error 
{{'__thread' variables must have global storage}}
-  template for (int x; static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}}
-  template for (int x; constinit auto y : {1, 2}); // expected-error {{local 
variable cannot be declared 'constinit'}}
-  template for (int x; consteval auto y : {1, 2});  // expected-error 
{{consteval can only be used in function declarations}}
-  template for (auto y : {abc, -+, }); // expected-error {{use of undeclared 
identifier 'abc'}} expected-error {{expected expression}}
+  template for (auto y : {1};
+  // expected-error@-1 {{expected ')'}}
+  // expected-note@-2 {{to match this '('}}
+  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (extern auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 'extern'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (register auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 
'register'}}
+  // expected-error@-2 {{ISO C++17 does not allow 'register' storage class 
specifier}}
+  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (__private_extern__ auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 'extern'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (extern static auto y : {1, 2});
+  // expected-error@-1 {{cannot combine with previous 'extern' declaration 
specifier}}
+  // expected-error@-2 {{expansion variable 'y' may not be declared 'extern'}}
+  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (static auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 'static'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (thread_local auto y : {1, 2});
+  // expected-error@-1 {{'thread_local' variables must have global storage}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (static thread_local auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 
'thread_local'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (__thread auto y : {1, 2});
+  // expected-error@-1 {{'__thread' variables must have global storage}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (static __thread auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 'static'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (constinit auto y : {1, 2});
+  // expected-error@-1 {{local variable cannot be declared 'constinit'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (consteval auto y : {1, 2});
+  // expected-error@-1 {{consteval can only be used in function declarations}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (int x; extern auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 'extern'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (int x; extern static auto y : {1, 2});
+  // expected-error@-1 {{cannot combine with previous 'extern' declaration 
specifier}}
+  // expected-error@-2 {{expansion variable 'y' may not be declared 'extern'}}
+  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (int x; static auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 'static'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (int x; thread_local auto y : {1, 2});
+  // expected-error@-1 {{'thread_local' variables must have global storage}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (int x; static thread_local auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 
'thread_local'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (int x; __thread auto y : {1, 2});
+  // expected-error@-1 {{'__thread' variables must have global storage}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (int x; static __thread auto y : {1, 2});
+  // expected-error@-1 {{expansion variable 'y' may not be declared 'static'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (int x; constinit auto y : {1, 2});
+  // expected-error@-1 {{local variable cannot be declared 'constinit'}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (int x; consteval auto y : {1, 2});
+  // expected-error@-1 {{consteval can only be used in function declarations}}
+  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (auto y : {abc, -+, });
+  // expected-error@-1 {{use of undeclared identifier 'abc'}}
+  // expected-error@-2 {{expected expression}}
+  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
   template for (3 : "error") // expected-error {{expansion statement 
declaration must declare a variable}} \
                                 expected-error {{expansion statement must use 
the syntax of a range-based for loop}}
     ;
@@ -46,18 +98,21 @@ void bad() {
   ; // Semicolon for synchronisation; otherwise, the parser skips over next 
statement...
   template do {} while (true); // expected-error {{expected '<' after 
'template'}}
   for template (int x : {}) {} // expected-error {{'for template' is invalid; 
use 'template for' instead}}
+  template for (int x : {1})
+    [ // brace-warning {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+      []] {}
 }
 
 void good() {
-  template for (auto y : {});
-  template for (auto y : {1, 2});
-  template for (int x; auto y : {1, 2});
-  template for (int x; int y : {1, 2});
-  template for (int x; constexpr auto y : {1, 2});
-  template for (int x; constexpr int y : {1, 2});
+  template for (auto y : {}); // brace-warning {{ISO C++ requires a compound 
statement to be the body of expansion statement}}
+  template for (auto y : {1, 2}); // brace-warning {{ISO C++ requires a 
compound statement to be the body of expansion statement}}
+  template for (int x; auto y : {1, 2}); // brace-warning {{ISO C++ requires a 
compound statement to be the body of expansion statement}}
+  template for (int x; int y : {1, 2}); // brace-warning {{ISO C++ requires a 
compound statement to be the body of expansion statement}}
+  template for (int x; constexpr auto y : {1, 2}); // brace-warning {{ISO C++ 
requires a compound statement to be the body of expansion statement}}
+  template for (int x; constexpr int y : {1, 2}); // brace-warning {{ISO C++ 
requires a compound statement to be the body of expansion statement}}
   template for (constexpr int a : {1, 2}) {
     template for (constexpr int b : {1, 2}) {
-      template for (constexpr int c : {1, 2});
+      template for (constexpr int c : {1, 2}); // brace-warning {{ISO C++ 
requires a compound statement to be the body of expansion statement}}
     }
   }
 }

>From fac01ce301392ae1b76057cf9935a6b00519a197 Mon Sep 17 00:00:00 2001
From: Yanzuo Liu <[email protected]>
Date: Tue, 14 Jul 2026 16:34:49 +0800
Subject: [PATCH 2/3] Address review comments

---
 .../clang/Basic/DiagnosticParseKinds.td       |   6 +-
 clang/lib/Parse/ParseStmt.cpp                 |   8 +-
 ...sion-statements-non-compound-stmt-body.cpp |  31 +++++
 .../Parser/cxx2c-expansion-statements.cpp     | 115 +++++-------------
 4 files changed, 68 insertions(+), 92 deletions(-)
 create mode 100644 
clang/test/Parser/cxx2c-expansion-statements-non-compound-stmt-body.cpp

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 389900040399a..88d08b3c4a03b 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -457,9 +457,9 @@ 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_requires_braced_body : ExtWarn<
-  "ISO C++ requires a compound statement to be the body of expansion 
statement">,
-  InGroup<DiagGroup<"expansion-stmt-braced-body">>, DefaultIgnore;
+def ext_expansion_stmt_missing_braces : Extension<
+  "ISO C++ requires a compound statement to be the body of an expansion 
statement">,
+  InGroup<DiagGroup<"expansion-stmt-missing-braces">>;
 
 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 bbde87794b652..bebcba038a20e 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2329,8 +2329,8 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
   // the other parts.
   getCurScope()->EnterLoopBody(PrecedingLabel);
 
-  bool BodyIsCompoundStmt = Tok.is(tok::l_brace);
   // attribute-specifier without attribute (`[[]]`) isn't in AST.
+  bool BodyStartsWithSquare = Tok.is(tok::l_square);
   SourceLocation BodyBeginLoc = Tok.getLocation();
 
   // C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
@@ -2345,7 +2345,7 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
   // for-init-statement/condition and a new scope for substatement in C++.
   //
   ParseScope InnerScope(this, Scope::DeclScope, C99orCXXorObjC,
-                        BodyIsCompoundStmt);
+                        Tok.is(tok::l_brace));
 
   // The body of the for loop has the same local mangling number as the
   // for-init-statement.
@@ -2383,8 +2383,8 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
       return StmtError();
     }
 
-    if (!BodyIsCompoundStmt)
-      Diag(BodyBeginLoc, diag::ext_expansion_stmt_requires_braced_body);
+    if (!isa<CompoundStmt>(Body.get()) || BodyStartsWithSquare)
+      Diag(BodyBeginLoc, diag::ext_expansion_stmt_missing_braces);
 
     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..fb434f62da902
--- /dev/null
+++ b/clang/test/Parser/cxx2c-expansion-statements-non-compound-stmt-body.cpp
@@ -0,0 +1,31 @@
+// 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 a 
compound statement to be the body of an expansion statement}}
+      ; // expected-warning {{ISO C++ requires a compound statement to be the 
body of an expansion statement}}
+  template for (int x : {1})
+    if (x) // expected-warning {{ISO C++ requires a compound statement to be 
the body of an expansion statement}}
+      ;
+  template for (int x : {1})
+    switch (x) // expected-warning {{ISO C++ requires a compound statement to 
be the body of an expansion statement}}
+      ;
+  template for (int x : {1})
+    for (;;) // expected-warning {{ISO C++ requires a compound statement to be 
the body of an expansion statement}}
+      ;
+  template for (int x : {1})
+    while (x) // expected-warning {{ISO C++ requires a compound statement to 
be the body of an expansion statement}}
+      ;
+  template for (int x : {1})
+    do // expected-warning {{ISO C++ requires a compound statement to be the 
body of an expansion statement}}
+      ;
+    while (x);
+  template for (int x : {1})
+    return; // expected-warning {{ISO C++ requires a compound statement to be 
the body of an expansion statement}}
+  template for (int x : {1})
+    [ // expected-warning {{ISO C++ requires a compound statement to be the 
body of an expansion statement}}
+      []] {}
+  template for (int x : {1})
+    foo: {} // expected-error {{labels are not allowed in expansion 
statements}}
+}
diff --git a/clang/test/Parser/cxx2c-expansion-statements.cpp 
b/clang/test/Parser/cxx2c-expansion-statements.cpp
index 2ca94270cd60a..736f9fead383c 100644
--- a/clang/test/Parser/cxx2c-expansion-statements.cpp
+++ b/clang/test/Parser/cxx2c-expansion-statements.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -verify
-// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -verify=expected,brace 
-Wexpansion-stmt-braced-body
 namespace std {
 template <typename T>
 struct initializer_list {
@@ -15,82 +14,31 @@ void bad() {
   template for (;); // expected-error {{expected ';' in 'for' statement 
specifier}} expected-error {{expansion statement must use the syntax of a 
range-based for loop}}
   template for (;;); // expected-error {{expansion statement must use the 
syntax of a range-based for loop}}
   template for (int x;;); // expected-error {{expansion statement must use the 
syntax of a range-based for loop}}
-  template for (x : {1});
-  // expected-error@-1 {{expansion statement requires type for expansion 
variable}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (x : {1}); // expected-error {{expansion statement requires 
type for expansion variable}}
   template for (: {1}); // expected-error {{expected expression}} 
expected-error {{expected ';' in 'for' statement specifier}} expected-error 
{{expansion statement must use the syntax of a range-based for loop}}
   template for (auto y : {1})]; // expected-error {{expected expression}}
-  template for (auto y : {1};
-  // expected-error@-1 {{expected ')'}}
-  // expected-note@-2 {{to match this '('}}
-  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (extern auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 'extern'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (register auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 
'register'}}
-  // expected-error@-2 {{ISO C++17 does not allow 'register' storage class 
specifier}}
-  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (__private_extern__ auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 'extern'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (extern static auto y : {1, 2});
-  // expected-error@-1 {{cannot combine with previous 'extern' declaration 
specifier}}
-  // expected-error@-2 {{expansion variable 'y' may not be declared 'extern'}}
-  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (static auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 'static'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (thread_local auto y : {1, 2});
-  // expected-error@-1 {{'thread_local' variables must have global storage}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (static thread_local auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 
'thread_local'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (__thread auto y : {1, 2});
-  // expected-error@-1 {{'__thread' variables must have global storage}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (static __thread auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 'static'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (constinit auto y : {1, 2});
-  // expected-error@-1 {{local variable cannot be declared 'constinit'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (consteval auto y : {1, 2});
-  // expected-error@-1 {{consteval can only be used in function declarations}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (int x; extern auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 'extern'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (int x; extern static auto y : {1, 2});
-  // expected-error@-1 {{cannot combine with previous 'extern' declaration 
specifier}}
-  // expected-error@-2 {{expansion variable 'y' may not be declared 'extern'}}
-  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (int x; static auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 'static'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (int x; thread_local auto y : {1, 2});
-  // expected-error@-1 {{'thread_local' variables must have global storage}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (int x; static thread_local auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 
'thread_local'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (int x; __thread auto y : {1, 2});
-  // expected-error@-1 {{'__thread' variables must have global storage}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (int x; static __thread auto y : {1, 2});
-  // expected-error@-1 {{expansion variable 'y' may not be declared 'static'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (int x; constinit auto y : {1, 2});
-  // expected-error@-1 {{local variable cannot be declared 'constinit'}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (int x; consteval auto y : {1, 2});
-  // expected-error@-1 {{consteval can only be used in function declarations}}
-  // brace-warning@-2 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-  template for (auto y : {abc, -+, });
-  // expected-error@-1 {{use of undeclared identifier 'abc'}}
-  // expected-error@-2 {{expected expression}}
-  // brace-warning@-3 {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
+  template for (auto y : {1}; // expected-error {{expected ')'}} expected-note 
{{to match this '('}}
+  template for (extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}}
+  template for (register auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'register'}} expected-error {{ISO C++17 does 
not allow 'register' storage class specifier}}
+  template for (__private_extern__ auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'extern'}}
+  template for (extern static auto y : {1, 2}); // expected-error {{cannot 
combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}}
+  template for (static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}}
+  template for (thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}}
+  template for (static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}}
+  template for (__thread auto y : {1, 2}); // expected-error {{'__thread' 
variables must have global storage}}
+  template for (static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}}
+  template for (constinit auto y : {1, 2}); // expected-error {{local variable 
cannot be declared 'constinit'}}
+  template for (consteval auto y : {1, 2});  // expected-error {{consteval can 
only be used in function declarations}}
+  template for (int x; extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}}
+  template for (int x; extern static auto y : {1, 2}); // expected-error 
{{cannot combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}}
+  template for (int x; static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}}
+  template for (int x; thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}}
+  template for (int x; static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}}
+  template for (int x; __thread auto y : {1, 2}); // expected-error 
{{'__thread' variables must have global storage}}
+  template for (int x; static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}}
+  template for (int x; constinit auto y : {1, 2}); // expected-error {{local 
variable cannot be declared 'constinit'}}
+  template for (int x; consteval auto y : {1, 2});  // expected-error 
{{consteval can only be used in function declarations}}
+  template for (auto y : {abc, -+, }); // expected-error {{use of undeclared 
identifier 'abc'}} expected-error {{expected expression}}
   template for (3 : "error") // expected-error {{expansion statement 
declaration must declare a variable}} \
                                 expected-error {{expansion statement must use 
the syntax of a range-based for loop}}
     ;
@@ -98,21 +46,18 @@ void bad() {
   ; // Semicolon for synchronisation; otherwise, the parser skips over next 
statement...
   template do {} while (true); // expected-error {{expected '<' after 
'template'}}
   for template (int x : {}) {} // expected-error {{'for template' is invalid; 
use 'template for' instead}}
-  template for (int x : {1})
-    [ // brace-warning {{ISO C++ requires a compound statement to be the body 
of expansion statement}}
-      []] {}
 }
 
 void good() {
-  template for (auto y : {}); // brace-warning {{ISO C++ requires a compound 
statement to be the body of expansion statement}}
-  template for (auto y : {1, 2}); // brace-warning {{ISO C++ requires a 
compound statement to be the body of expansion statement}}
-  template for (int x; auto y : {1, 2}); // brace-warning {{ISO C++ requires a 
compound statement to be the body of expansion statement}}
-  template for (int x; int y : {1, 2}); // brace-warning {{ISO C++ requires a 
compound statement to be the body of expansion statement}}
-  template for (int x; constexpr auto y : {1, 2}); // brace-warning {{ISO C++ 
requires a compound statement to be the body of expansion statement}}
-  template for (int x; constexpr int y : {1, 2}); // brace-warning {{ISO C++ 
requires a compound statement to be the body of expansion statement}}
+  template for (auto y : {});
+  template for (auto y : {1, 2});
+  template for (int x; auto y : {1, 2});
+  template for (int x; int y : {1, 2});
+  template for (int x; constexpr auto y : {1, 2});
+  template for (int x; constexpr int y : {1, 2});
   template for (constexpr int a : {1, 2}) {
     template for (constexpr int b : {1, 2}) {
-      template for (constexpr int c : {1, 2}); // brace-warning {{ISO C++ 
requires a compound statement to be the body of expansion statement}}
+      template for (constexpr int c : {1, 2});
     }
   }
 }

>From 6e840d8d898306d4daf30f5bfc9c0264c599f2b9 Mon Sep 17 00:00:00 2001
From: Yanzuo Liu <[email protected]>
Date: Tue, 14 Jul 2026 22:00:15 +0800
Subject: [PATCH 3/3] Move comment to where the variable is used

---
 clang/lib/Parse/ParseStmt.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index bebcba038a20e..b72f28e4aac6d 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2329,7 +2329,6 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
   // the other parts.
   getCurScope()->EnterLoopBody(PrecedingLabel);
 
-  // attribute-specifier without attribute (`[[]]`) isn't in AST.
   bool BodyStartsWithSquare = Tok.is(tok::l_square);
   SourceLocation BodyBeginLoc = Tok.getLocation();
 
@@ -2383,6 +2382,7 @@ StmtResult Parser::ParseForStatement(SourceLocation 
*TrailingElseLoc,
       return StmtError();
     }
 
+    // attribute-specifier without attribute (`[[]]`) isn't in AST.
     if (!isa<CompoundStmt>(Body.get()) || BodyStartsWithSquare)
       Diag(BodyBeginLoc, diag::ext_expansion_stmt_missing_braces);
 

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

Reply via email to