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
