[clang] d13b862 - [clang][Parser] Warn when the body of expansion statement is not a compound statement (#209229)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 21 01:10:02 PDT 2026
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}}
+}
More information about the cfe-commits
mailing list