[llvm-branch-commits] [clang] release/23.x: [clang][Parser] Warn when the body of expansion statement is not a compound statement (#209229) (PR #210908)
Douglas Yung via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jul 22 06:59:03 PDT 2026
https://github.com/dyung updated https://github.com/llvm/llvm-project/pull/210908
>From 2f8eaf6ef04cb81fc98c30c1a8dd7fa1a0f4c43e Mon Sep 17 00:00:00 2001
From: Yanzuo Liu <zwuis at outlook.com>
Date: Tue, 21 Jul 2026 16:09:56 +0800
Subject: [PATCH] [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_
(cherry picked from commit d13b8625eef0941f48b5af74e9fab953b6430eb2)
---
clang/include/clang/Basic/DiagnosticGroups.td | 1 +
.../clang/Basic/DiagnosticParseKinds.td | 6 +++
clang/lib/Parse/ParseStmt.cpp | 11 +++++
...sion-statements-non-compound-stmt-body.cpp | 47 +++++++++++++++++++
4 files changed, 65 insertions(+)
create mode 100644 clang/test/Parser/cxx2c-expansion-statements-non-compound-stmt-body.cpp
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 55b26deed0750..7671f003c8b80 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -457,6 +457,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 bdaea72cf52a1..44b51a985f2ff 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2329,6 +2329,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.
@@ -2379,6 +2382,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}}
+}
More information about the llvm-branch-commits
mailing list