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
