https://github.com/bassiounix updated https://github.com/llvm/llvm-project/pull/198244
>From 4b23504a24dd2eed4681159da7d26681e2508443 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Mon, 18 May 2026 10:05:00 +0300 Subject: [PATCH 01/21] [Clang][C2y] Add support for if declaration --- .../clang/Basic/DiagnosticParseKinds.td | 2 + clang/include/clang/Parse/Parser.h | 10 ++-- clang/lib/Parse/ParseDecl.cpp | 5 +- clang/lib/Parse/ParseExprCXX.cpp | 47 +++++++++++---- clang/lib/Parse/ParseStmt.cpp | 2 +- clang/lib/Parse/ParseTentative.cpp | 4 +- clang/test/C/C2y/n3267.c | 59 +++++++++++++++++++ 7 files changed, 107 insertions(+), 22 deletions(-) create mode 100644 clang/test/C/C2y/n3267.c diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 7bcd1870a2600..9c4527764226b 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -220,6 +220,8 @@ def ext_c2y_case_range : Extension< "case ranges are a C2y extension">, InGroup<C2y>; def err_c2y_labeled_break_continue : Error< "named %select{'break'|'continue'}0 is only supported in C2y">; +def err_c2y_first_condition_clause_is_not_declaration : Error< + "first clause in condition must be a declaration">; // Generic errors. def err_expected_expression : Error<"expected expression">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index dc3dc8a4ae0e9..5182e2849f8d7 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5039,12 +5039,10 @@ class Parser : public CodeCompletionHandler { /// appropriate moment for a 'for' loop. /// /// \returns The parsed condition. - Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt, - SourceLocation Loc, - Sema::ConditionKind CK, - bool MissingOK, - ForRangeInfo *FRI = nullptr, - bool EnterForConditionScope = false); + Sema::ConditionResult ParseCXXCondition( + StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK, + bool MissingOK, ForRangeInfo *FRI = nullptr, + bool EnterForConditionScope = false, bool isSecondCallForIfCond = false); DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context, ParsedAttributes &Attrs); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 75ad821c245a5..0635508cd0713 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2162,10 +2162,11 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParsedAttributes LocalAttrs(AttrFactory); LocalAttrs.takeAllPrependingFrom(Attrs); ParsingDeclarator D(*this, DS, LocalAttrs, Context); - if (TemplateInfo.TemplateParams) + if (!getLangOpts().C2y && TemplateInfo.TemplateParams) D.setTemplateParameterLists(*TemplateInfo.TemplateParams); bool IsTemplateSpecOrInst = + !getLangOpts().C2y && (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation || TemplateInfo.Kind == ParsedTemplateKind::ExplicitSpecialization); SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); @@ -2185,7 +2186,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, while (MaybeParseHLSLAnnotations(D)) ; - if (Tok.is(tok::kw_requires)) + if (!getLangOpts().C2y && Tok.is(tok::kw_requires)) ParseTrailingRequiresClauseWithScope(D); // Save late-parsed attributes for now; they need to be parsed in the diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 39c61f4b5bf5c..85782255a1b97 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1868,7 +1868,8 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context, Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK, bool MissingOK, - ForRangeInfo *FRI, bool EnterForConditionScope) { + ForRangeInfo *FRI, bool EnterForConditionScope, + bool isSecondCallForIfCond) { // Helper to ensure we always enter a continue/break scope if requested. struct ForConditionScopeRAII { Scope *S; @@ -1883,6 +1884,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, S->setIsConditionVarScope(false); } } ForConditionScope{EnterForConditionScope ? getCurScope() : nullptr}; + bool parsingIfOrSwitchCondition = !FRI && !EnterForConditionScope; ParenBraceBracketBalancer BalancerRAIIObj(*this); PreferredType.enterCondition(Actions, Tok.getLocation()); @@ -1898,10 +1900,11 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, MaybeParseCXX11Attributes(attrs); const auto WarnOnInit = [this, &CK] { - Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 - ? diag::warn_cxx14_compat_init_statement - : diag::ext_init_statement) - << (CK == Sema::ConditionKind::Switch); + if (!getLangOpts().C2y) + Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 + ? diag::warn_cxx14_compat_init_statement + : diag::ext_init_statement) + << (CK == Sema::ConditionKind::Switch); }; // Determine what kind of thing we have. @@ -1924,7 +1927,9 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, } ConsumeToken(); *InitStmt = Actions.ActOnNullStmt(SemiLoc); - return ParseCXXCondition(nullptr, Loc, CK, MissingOK); + return ParseCXXCondition(nullptr, Loc, CK, MissingOK, FRI, + EnterForConditionScope, + parsingIfOrSwitchCondition); } EnterExpressionEvaluationContext Eval( @@ -1939,10 +1944,22 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, return Sema::ConditionError(); if (InitStmt && Tok.is(tok::semi)) { + if (getLangOpts().C2y && parsingIfOrSwitchCondition && + !isSecondCallForIfCond) + // C2y only permits declaration in the first clause of an if condition, + // so it makes sense to error out in other condition. We can stop + // parsing here and just report an error but we chose to continue to + // generate an error about the second clause of the condition since + // there's a ';' found. + Diag(Tok.getLocation(), + diag::err_c2y_first_condition_clause_is_not_declaration); + WarnOnInit(); *InitStmt = Actions.ActOnExprStmt(Expr.get()); ConsumeToken(); - return ParseCXXCondition(nullptr, Loc, CK, MissingOK); + return ParseCXXCondition(nullptr, Loc, CK, MissingOK, FRI, + EnterForConditionScope, + parsingIfOrSwitchCondition); } return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK, @@ -1953,7 +1970,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, WarnOnInit(); DeclGroupPtrTy DG; SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - if (Tok.is(tok::kw_using)) + if (!getLangOpts().C2y && Tok.is(tok::kw_using)) DG = ParseAliasDeclarationInInitStatement( DeclaratorContext::SelectionInit, attrs); else { @@ -1962,7 +1979,9 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, attrs, DeclSpecAttrs, /*RequireSemi=*/true); } *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd); - return ParseCXXCondition(nullptr, Loc, CK, MissingOK); + return ParseCXXCondition(nullptr, Loc, CK, MissingOK, FRI, + EnterForConditionScope, + parsingIfOrSwitchCondition); } case ConditionOrInitStatement::ForRangeDecl: { @@ -1978,7 +1997,12 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, return Sema::ConditionResult(); } - case ConditionOrInitStatement::ConditionDecl: + case ConditionOrInitStatement::ConditionDecl: { + if (getLangOpts().C2y && isSecondCallForIfCond) { + Diag(Tok.getLocation(), diag::err_expected_expression); + return Sema::ConditionError(); + } + } break; case ConditionOrInitStatement::Error: break; } @@ -2007,7 +2031,8 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, } // If attributes are present, parse them. - MaybeParseGNUAttributes(DeclaratorInfo); + if (!getLangOpts().C2y) + MaybeParseGNUAttributes(DeclaratorInfo); // Type-check the declaration itself. DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(), diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 1a45ed66950be..301898fb3955f 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1264,7 +1264,7 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, T.consumeOpen(); SourceLocation Start = Tok.getLocation(); - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().C2y) { Cond = ParseCXXCondition(InitStmt, Loc, CK, false); } else { ExprResult CondExpr = ParseExpression(); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index f77b1001332fe..8c4b328fe538f 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -453,7 +453,7 @@ Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement, ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement, CanBeForRangeDecl); - if (CanBeInitStatement && Tok.is(tok::kw_using)) + if (!getLangOpts().C2y && CanBeInitStatement && Tok.is(tok::kw_using)) return ConditionOrInitStatement::InitStmtDecl; if (State.update(isCXXDeclarationSpecifier(ImplicitTypenameContext::No))) return State.result(); @@ -1065,7 +1065,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, // Check for need to substitute AltiVec __vector keyword // for "vector" identifier. - if (TryAltiVecVectorToken()) + if (!getLangOpts().C2y && TryAltiVecVectorToken()) return TPResult::True; const Token &Next = NextToken(); diff --git a/clang/test/C/C2y/n3267.c b/clang/test/C/C2y/n3267.c new file mode 100644 index 0000000000000..df3dbc7561ff2 --- /dev/null +++ b/clang/test/C/C2y/n3267.c @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -std=c2y -verify %s + +bool test_if() { + if (true) {} + if (bool x = true; x) {} + if (bool x = false) return x; + if ([[maybe_unused]] bool x = true) {} + if (bool x [[maybe_unused]] = true) {} + if ([[maybe_unused]] int x = 3; x > 0) {} + return false; +} + +int test_switch() { + int y = 1; + switch (y) {} + + switch (int x = 1; x) { + default: + y += x; + } + + switch (int x [[maybe_unused]] = 1) {} + switch ([[maybe_unused]] int x = 1) {} + + switch (int x = 1) { + default: + return y + x; + } +} + +bool negative_test_if() { + if (true; true) {} /* expected-error {{first clause in condition must be a declaration}} + expected-warning {{expression result unused}}*/ + if (true; ) {} /* expected-error {{first clause in condition must be a declaration}} + expected-error {{expected expression}} + expected-warning {{expression result unused}} */ + if (bool x = true; bool y = x) return y; /* expected-error {{expected expression}} + expected-error {{use of undeclared identifier 'y'}} */ + if (true; bool y = true) return y; /* expected-error {{first clause in condition must be a declaration}} + expected-error {{expected expression}} + expected-error {{use of undeclared identifier 'y'}} + expected-warning {{expression result unused}}*/ + return false; +} + +int negative_test_switch() { + switch (true; 1) { /* expected-error {{first clause in condition must be a declaration}} + expected-warning {{expression result unused}} */ + default: + break; + } + switch (true; ) {} /* expected-error {{first clause in condition must be a declaration}} + expected-error {{expected expression}} + expected-warning {{expression result unused}} */ + switch (int x = 1; int y = x) { // expected-error {{expected expression}} + default: + return y; // expected-error {{use of undeclared identifier 'y'}} + } +} >From 0d0f44120e207a70a45151bd407342082bc95970 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Mon, 18 May 2026 11:03:57 +0300 Subject: [PATCH 02/21] add exposure --- clang/docs/ReleaseNotes.rst | 32 +++++++++++++++++++++++++++----- clang/www/c_status.html | 2 +- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4b0eb5b9d8505..cb14655b517d1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -177,6 +177,28 @@ C Language Changes C2y Feature Support ^^^^^^^^^^^^^^^^^^^ +- Clang now supports C2y's new syntax for if and switch statements with initializer and condition variables, as specified in `N3356 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3356.htm>`_. For example: + + .. code-block:: c + + if (bool x = true; x) { + // ... + } + + if (bool x = true) { + // ... + } + + // attribute list on declarations are also supported + switch ([[maybe_unused]] int x = 1) { + default: + // ... + } + + if (bool x [[maybe_unused]] = true; x) { + // ... + } + - Implemented the type-specific C2y ``<stdbit.h>`` rotate functions with constexpr evaluation support: ``stdc_rotate_left_{uc,us,ui,ul,ull}`` and @@ -353,7 +375,7 @@ Attribute Changes in Clang - The ``[[clang::unsafe_buffer_usage]]`` attribute is now supported in API notes. For example: - + .. code-block:: yaml Functions: @@ -751,10 +773,10 @@ clang-format ------------ - Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space between the '-'/'+' and the return type in Objective-C method declarations -- Deprecate the ``BinPackParameters`` and ``BinPackArguments`` options and replace - them with the ``PackParameters`` and ``PackArguments`` structs (respectively) to - unify packing behavior. Add the ``BreakAfter`` option to the structs, allowing - parameter and argument lists to be formatted with one parameter/argument on each +- Deprecate the ``BinPackParameters`` and ``BinPackArguments`` options and replace + them with the ``PackParameters`` and ``PackArguments`` structs (respectively) to + unify packing behavior. Add the ``BreakAfter`` option to the structs, allowing + parameter and argument lists to be formatted with one parameter/argument on each line if they exceed the specified count. - Add ``AfterComma`` value to ``BreakConstructorInitializers`` to allow breaking constructor initializers after commas, keeping the colon on the same line. diff --git a/clang/www/c_status.html b/clang/www/c_status.html index 5270033471167..3ae0e0a7d3146 100644 --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -181,7 +181,7 @@ <h2 id="c2y">C2y implementation status</h2> <tr> <td>'if' declarations, v2</td> <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3356.htm">N3356</a></td> - <td class="none" align="center">No</td> + <td class="unreleased" align="center">Clang 23</td> </tr> <tr> <td>Allowing stricter alignment for atomic types</td> >From 0e20732a06e32b6857178c03f2e77670f5cbd3b3 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Tue, 19 May 2026 01:33:12 +0300 Subject: [PATCH 03/21] address diff in release notes --- clang/docs/ReleaseNotes.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index cb14655b517d1..afea236bdb012 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -375,7 +375,7 @@ Attribute Changes in Clang - The ``[[clang::unsafe_buffer_usage]]`` attribute is now supported in API notes. For example: - + .. code-block:: yaml Functions: @@ -773,10 +773,10 @@ clang-format ------------ - Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space between the '-'/'+' and the return type in Objective-C method declarations -- Deprecate the ``BinPackParameters`` and ``BinPackArguments`` options and replace - them with the ``PackParameters`` and ``PackArguments`` structs (respectively) to - unify packing behavior. Add the ``BreakAfter`` option to the structs, allowing - parameter and argument lists to be formatted with one parameter/argument on each +- Deprecate the ``BinPackParameters`` and ``BinPackArguments`` options and replace + them with the ``PackParameters`` and ``PackArguments`` structs (respectively) to + unify packing behavior. Add the ``BreakAfter`` option to the structs, allowing + parameter and argument lists to be formatted with one parameter/argument on each line if they exceed the specified count. - Add ``AfterComma`` value to ``BreakConstructorInitializers`` to allow breaking constructor initializers after commas, keeping the colon on the same line. >From 46da0c5e77131686dab5ce8d090e7a7a99d372de Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Tue, 19 May 2026 01:34:57 +0300 Subject: [PATCH 04/21] rename `isSecondCallForIfCond` to `isParsingSecondClauseOfC2yIfCondition` --- clang/include/clang/Parse/Parser.h | 10 ++++++---- clang/lib/Parse/ParseExprCXX.cpp | 17 +++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 5182e2849f8d7..1500bcef9d434 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5039,10 +5039,12 @@ class Parser : public CodeCompletionHandler { /// appropriate moment for a 'for' loop. /// /// \returns The parsed condition. - Sema::ConditionResult ParseCXXCondition( - StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK, - bool MissingOK, ForRangeInfo *FRI = nullptr, - bool EnterForConditionScope = false, bool isSecondCallForIfCond = false); + Sema::ConditionResult + ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, + Sema::ConditionKind CK, bool MissingOK, + ForRangeInfo *FRI = nullptr, + bool EnterForConditionScope = false, + bool isParsingSecondClauseOfC2yIfCondition = false); DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context, ParsedAttributes &Attrs); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 85782255a1b97..3531f62cdfaf2 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1869,7 +1869,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK, bool MissingOK, ForRangeInfo *FRI, bool EnterForConditionScope, - bool isSecondCallForIfCond) { + bool isParsingSecondClauseOfC2yIfCondition) { // Helper to ensure we always enter a continue/break scope if requested. struct ForConditionScopeRAII { Scope *S; @@ -1884,7 +1884,8 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, S->setIsConditionVarScope(false); } } ForConditionScope{EnterForConditionScope ? getCurScope() : nullptr}; - bool parsingIfOrSwitchCondition = !FRI && !EnterForConditionScope; + bool parsingC2yIfOrSwitchCondition = + getLangOpts().C2y && !FRI && !EnterForConditionScope; ParenBraceBracketBalancer BalancerRAIIObj(*this); PreferredType.enterCondition(Actions, Tok.getLocation()); @@ -1929,7 +1930,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, *InitStmt = Actions.ActOnNullStmt(SemiLoc); return ParseCXXCondition(nullptr, Loc, CK, MissingOK, FRI, EnterForConditionScope, - parsingIfOrSwitchCondition); + parsingC2yIfOrSwitchCondition); } EnterExpressionEvaluationContext Eval( @@ -1944,8 +1945,8 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, return Sema::ConditionError(); if (InitStmt && Tok.is(tok::semi)) { - if (getLangOpts().C2y && parsingIfOrSwitchCondition && - !isSecondCallForIfCond) + if (parsingC2yIfOrSwitchCondition && + !isParsingSecondClauseOfC2yIfCondition) // C2y only permits declaration in the first clause of an if condition, // so it makes sense to error out in other condition. We can stop // parsing here and just report an error but we chose to continue to @@ -1959,7 +1960,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, ConsumeToken(); return ParseCXXCondition(nullptr, Loc, CK, MissingOK, FRI, EnterForConditionScope, - parsingIfOrSwitchCondition); + parsingC2yIfOrSwitchCondition); } return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK, @@ -1981,7 +1982,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd); return ParseCXXCondition(nullptr, Loc, CK, MissingOK, FRI, EnterForConditionScope, - parsingIfOrSwitchCondition); + parsingC2yIfOrSwitchCondition); } case ConditionOrInitStatement::ForRangeDecl: { @@ -1998,7 +1999,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, } case ConditionOrInitStatement::ConditionDecl: { - if (getLangOpts().C2y && isSecondCallForIfCond) { + if (getLangOpts().C2y && isParsingSecondClauseOfC2yIfCondition) { Diag(Tok.getLocation(), diag::err_expected_expression); return Sema::ConditionError(); } >From 001d432f4743cb2f9eb4a6aebbf295330e18b646 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Tue, 19 May 2026 02:34:23 +0300 Subject: [PATCH 05/21] move checks --- clang/lib/Parse/ParseExprCXX.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 3531f62cdfaf2..2e92ea3c511dd 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1998,13 +1998,12 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, return Sema::ConditionResult(); } - case ConditionOrInitStatement::ConditionDecl: { + case ConditionOrInitStatement::ConditionDecl: + case ConditionOrInitStatement::Error: if (getLangOpts().C2y && isParsingSecondClauseOfC2yIfCondition) { Diag(Tok.getLocation(), diag::err_expected_expression); return Sema::ConditionError(); } - } break; - case ConditionOrInitStatement::Error: break; } @@ -2032,8 +2031,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, } // If attributes are present, parse them. - if (!getLangOpts().C2y) - MaybeParseGNUAttributes(DeclaratorInfo); + MaybeParseGNUAttributes(DeclaratorInfo); // Type-check the declaration itself. DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(), >From 19ddb57fdf9d91d4536caf9dcadfcb670c7709c4 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Tue, 19 May 2026 20:13:05 +0300 Subject: [PATCH 06/21] change camelCase to PascalCase --- clang/include/clang/Parse/Parser.h | 2 +- clang/lib/Parse/ParseExprCXX.cpp | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 1500bcef9d434..297bdb373bc7d 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5044,7 +5044,7 @@ class Parser : public CodeCompletionHandler { Sema::ConditionKind CK, bool MissingOK, ForRangeInfo *FRI = nullptr, bool EnterForConditionScope = false, - bool isParsingSecondClauseOfC2yIfCondition = false); + bool ParsingSecondClauseOfC2yIfCondition = false); DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context, ParsedAttributes &Attrs); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 2e92ea3c511dd..9117e90fa78d8 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1869,7 +1869,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK, bool MissingOK, ForRangeInfo *FRI, bool EnterForConditionScope, - bool isParsingSecondClauseOfC2yIfCondition) { + bool ParsingSecondClauseOfC2yIfCondition) { // Helper to ensure we always enter a continue/break scope if requested. struct ForConditionScopeRAII { Scope *S; @@ -1945,8 +1945,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, return Sema::ConditionError(); if (InitStmt && Tok.is(tok::semi)) { - if (parsingC2yIfOrSwitchCondition && - !isParsingSecondClauseOfC2yIfCondition) + if (parsingC2yIfOrSwitchCondition && !ParsingSecondClauseOfC2yIfCondition) // C2y only permits declaration in the first clause of an if condition, // so it makes sense to error out in other condition. We can stop // parsing here and just report an error but we chose to continue to @@ -2000,7 +1999,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, case ConditionOrInitStatement::ConditionDecl: case ConditionOrInitStatement::Error: - if (getLangOpts().C2y && isParsingSecondClauseOfC2yIfCondition) { + if (getLangOpts().C2y && ParsingSecondClauseOfC2yIfCondition) { Diag(Tok.getLocation(), diag::err_expected_expression); return Sema::ConditionError(); } >From 946d453d11c9cf7cb119ed4fc9adda35a6fbfea3 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Tue, 19 May 2026 20:25:51 +0300 Subject: [PATCH 07/21] remove unnecessary checks --- clang/lib/Parse/ParseDecl.cpp | 5 ++--- clang/lib/Parse/ParseExprCXX.cpp | 4 ++-- clang/lib/Parse/ParseTentative.cpp | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0635508cd0713..75ad821c245a5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2162,11 +2162,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParsedAttributes LocalAttrs(AttrFactory); LocalAttrs.takeAllPrependingFrom(Attrs); ParsingDeclarator D(*this, DS, LocalAttrs, Context); - if (!getLangOpts().C2y && TemplateInfo.TemplateParams) + if (TemplateInfo.TemplateParams) D.setTemplateParameterLists(*TemplateInfo.TemplateParams); bool IsTemplateSpecOrInst = - !getLangOpts().C2y && (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation || TemplateInfo.Kind == ParsedTemplateKind::ExplicitSpecialization); SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); @@ -2186,7 +2185,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, while (MaybeParseHLSLAnnotations(D)) ; - if (!getLangOpts().C2y && Tok.is(tok::kw_requires)) + if (Tok.is(tok::kw_requires)) ParseTrailingRequiresClauseWithScope(D); // Save late-parsed attributes for now; they need to be parsed in the diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 9117e90fa78d8..4a9f671ef72ab 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1885,7 +1885,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, } } ForConditionScope{EnterForConditionScope ? getCurScope() : nullptr}; bool parsingC2yIfOrSwitchCondition = - getLangOpts().C2y && !FRI && !EnterForConditionScope; + getLangOpts().C2y && !EnterForConditionScope; ParenBraceBracketBalancer BalancerRAIIObj(*this); PreferredType.enterCondition(Actions, Tok.getLocation()); @@ -1970,7 +1970,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, WarnOnInit(); DeclGroupPtrTy DG; SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - if (!getLangOpts().C2y && Tok.is(tok::kw_using)) + if (Tok.is(tok::kw_using)) DG = ParseAliasDeclarationInInitStatement( DeclaratorContext::SelectionInit, attrs); else { diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 8c4b328fe538f..f77b1001332fe 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -453,7 +453,7 @@ Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement, ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement, CanBeForRangeDecl); - if (!getLangOpts().C2y && CanBeInitStatement && Tok.is(tok::kw_using)) + if (CanBeInitStatement && Tok.is(tok::kw_using)) return ConditionOrInitStatement::InitStmtDecl; if (State.update(isCXXDeclarationSpecifier(ImplicitTypenameContext::No))) return State.result(); @@ -1065,7 +1065,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, // Check for need to substitute AltiVec __vector keyword // for "vector" identifier. - if (!getLangOpts().C2y && TryAltiVecVectorToken()) + if (TryAltiVecVectorToken()) return TPResult::True; const Token &Next = NextToken(); >From 403880ed7de08fab16a49d3c62fe4af7a7611126 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Wed, 20 May 2026 05:28:08 +0300 Subject: [PATCH 08/21] rethink parsing --- clang/docs/LanguageExtensions.rst | 1 + .../clang/Basic/DiagnosticParseKinds.td | 6 +++ clang/include/clang/Parse/Parser.h | 12 +++--- clang/lib/Parse/ParseExprCXX.cpp | 37 +++++-------------- clang/lib/Parse/ParseStmt.cpp | 34 +++++++++++------ clang/test/C/C2y/n3267.c | 7 ++-- 6 files changed, 48 insertions(+), 49 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 03cb02deb5e7f..33f07f86e1e23 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2014,6 +2014,7 @@ Octal literals prefixed with ``0o`` or ``0O`` C ``_Generic`` with a type operand (N3260) C2y C89, C++ ``++``/``--`` on ``_Complex`` value (N3259) C2y C89, C++ ``__COUNTER__`` (N3457) C2y C89, C++ +If declarations (N3356) C2y C99 ============================================= ================================ ============= ============= Builtin type aliases diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 9c4527764226b..092fe1ed5344d 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -169,6 +169,12 @@ def ext_c2y_generic_with_type_arg : Extension< def warn_c2y_compat_generic_with_type_arg : Warning< "passing a type argument as the first operand to '_Generic' is incompatible " "with C standards before C2y">, InGroup<CPre2yCompat>, DefaultIgnore; +def warn_c2y_compat_init_statement : Warning< + "%select{if|switch}0 initialization statements are incompatible with " + "C standards before C2y">, DefaultIgnore, InGroup<CPre2yCompat>; +def ext_c2y_init_statement : ExtWarn< + "'%select{if|switch}0' initialization statements are a C2y extension">, + InGroup<C2y>; def ext_c99_feature : Extension< "'%0' is a C99 extension">, InGroup<C99>; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 297bdb373bc7d..dc3dc8a4ae0e9 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5039,12 +5039,12 @@ class Parser : public CodeCompletionHandler { /// appropriate moment for a 'for' loop. /// /// \returns The parsed condition. - Sema::ConditionResult - ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, - Sema::ConditionKind CK, bool MissingOK, - ForRangeInfo *FRI = nullptr, - bool EnterForConditionScope = false, - bool ParsingSecondClauseOfC2yIfCondition = false); + Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt, + SourceLocation Loc, + Sema::ConditionKind CK, + bool MissingOK, + ForRangeInfo *FRI = nullptr, + bool EnterForConditionScope = false); DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context, ParsedAttributes &Attrs); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 4a9f671ef72ab..d23c0ab1588d3 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1868,8 +1868,7 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context, Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK, bool MissingOK, - ForRangeInfo *FRI, bool EnterForConditionScope, - bool ParsingSecondClauseOfC2yIfCondition) { + ForRangeInfo *FRI, bool EnterForConditionScope) { // Helper to ensure we always enter a continue/break scope if requested. struct ForConditionScopeRAII { Scope *S; @@ -1884,8 +1883,6 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, S->setIsConditionVarScope(false); } } ForConditionScope{EnterForConditionScope ? getCurScope() : nullptr}; - bool parsingC2yIfOrSwitchCondition = - getLangOpts().C2y && !EnterForConditionScope; ParenBraceBracketBalancer BalancerRAIIObj(*this); PreferredType.enterCondition(Actions, Tok.getLocation()); @@ -1901,11 +1898,16 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, MaybeParseCXX11Attributes(attrs); const auto WarnOnInit = [this, &CK] { - if (!getLangOpts().C2y) + if (getLangOpts().CPlusPlus) Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_init_statement : diag::ext_init_statement) << (CK == Sema::ConditionKind::Switch); + else + Diag(Tok.getLocation(), getLangOpts().C2y + ? diag::warn_c2y_compat_init_statement + : diag::ext_c2y_init_statement) + << (CK == Sema::ConditionKind::Switch); }; // Determine what kind of thing we have. @@ -1928,9 +1930,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, } ConsumeToken(); *InitStmt = Actions.ActOnNullStmt(SemiLoc); - return ParseCXXCondition(nullptr, Loc, CK, MissingOK, FRI, - EnterForConditionScope, - parsingC2yIfOrSwitchCondition); + return ParseCXXCondition(nullptr, Loc, CK, MissingOK); } EnterExpressionEvaluationContext Eval( @@ -1945,21 +1945,10 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, return Sema::ConditionError(); if (InitStmt && Tok.is(tok::semi)) { - if (parsingC2yIfOrSwitchCondition && !ParsingSecondClauseOfC2yIfCondition) - // C2y only permits declaration in the first clause of an if condition, - // so it makes sense to error out in other condition. We can stop - // parsing here and just report an error but we chose to continue to - // generate an error about the second clause of the condition since - // there's a ';' found. - Diag(Tok.getLocation(), - diag::err_c2y_first_condition_clause_is_not_declaration); - WarnOnInit(); *InitStmt = Actions.ActOnExprStmt(Expr.get()); ConsumeToken(); - return ParseCXXCondition(nullptr, Loc, CK, MissingOK, FRI, - EnterForConditionScope, - parsingC2yIfOrSwitchCondition); + return ParseCXXCondition(nullptr, Loc, CK, MissingOK); } return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK, @@ -1979,9 +1968,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, attrs, DeclSpecAttrs, /*RequireSemi=*/true); } *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd); - return ParseCXXCondition(nullptr, Loc, CK, MissingOK, FRI, - EnterForConditionScope, - parsingC2yIfOrSwitchCondition); + return ParseCXXCondition(nullptr, Loc, CK, MissingOK); } case ConditionOrInitStatement::ForRangeDecl: { @@ -1999,10 +1986,6 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, case ConditionOrInitStatement::ConditionDecl: case ConditionOrInitStatement::Error: - if (getLangOpts().C2y && ParsingSecondClauseOfC2yIfCondition) { - Diag(Tok.getLocation(), diag::err_expected_expression); - return Sema::ConditionError(); - } break; } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 301898fb3955f..13b549ad6e2d6 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1264,18 +1264,7 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, T.consumeOpen(); SourceLocation Start = Tok.getLocation(); - if (getLangOpts().CPlusPlus || getLangOpts().C2y) { - Cond = ParseCXXCondition(InitStmt, Loc, CK, false); - } else { - ExprResult CondExpr = ParseExpression(); - - // If required, convert to a boolean value. - if (CondExpr.isInvalid()) - Cond = Sema::ConditionError(); - else - Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK, - /*MissingOK=*/false); - } + Cond = ParseCXXCondition(InitStmt, Loc, CK, false); // If the parser was confused by the condition and we don't have a ')', try to // recover by skipping ahead to a semi and bailing out. If condexp is @@ -1297,6 +1286,27 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, /*MissingOK=*/false); } + if (getLangOpts().C99 && InitStmt->get() != nullptr && + InitStmt->get()->getStmtClass() != Stmt::DeclStmtClass){ + // C2y only permits declaration in the first clause of an if condition, + // so it makes sense to error out in other conditions. + Diag(InitStmt->get()->getBeginLoc(), + diag::err_c2y_first_condition_clause_is_not_declaration) + << InitStmt->get()->getSourceRange(); + Cond = Sema::ConditionError(); + return true; + } + + if (getLangOpts().C99 && InitStmt->get() != nullptr && + Cond.get().first != nullptr){ + // C2y only permits expression in the second clause of an if condition, + // so it makes sense to error out in other conditions. + Diag(Cond.get().first->getBeginLoc(), diag::err_expected_expression) + << Cond.get().first->getSourceRange(); + Cond = Sema::ConditionError(); + return true; + } + // Either the condition is valid or the rparen is present. T.consumeClose(); LParenLoc = T.getOpenLocation(); diff --git a/clang/test/C/C2y/n3267.c b/clang/test/C/C2y/n3267.c index df3dbc7561ff2..6cc2bdf4bc4a4 100644 --- a/clang/test/C/C2y/n3267.c +++ b/clang/test/C/C2y/n3267.c @@ -34,11 +34,10 @@ bool negative_test_if() { if (true; ) {} /* expected-error {{first clause in condition must be a declaration}} expected-error {{expected expression}} expected-warning {{expression result unused}} */ - if (bool x = true; bool y = x) return y; /* expected-error {{expected expression}} - expected-error {{use of undeclared identifier 'y'}} */ + if (bool x = true; bool y = x) return y; // expected-error {{expected expression}} + if (true; bool y = true) return y; /* expected-error {{first clause in condition must be a declaration}} expected-error {{expected expression}} - expected-error {{use of undeclared identifier 'y'}} expected-warning {{expression result unused}}*/ return false; } @@ -54,6 +53,6 @@ int negative_test_switch() { expected-warning {{expression result unused}} */ switch (int x = 1; int y = x) { // expected-error {{expected expression}} default: - return y; // expected-error {{use of undeclared identifier 'y'}} + return y; } } >From 52998b10b7f6c1f3031c546d67cdbd6b14a64ee0 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Wed, 20 May 2026 05:29:41 +0300 Subject: [PATCH 09/21] format --- clang/lib/Parse/ParseStmt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 13b549ad6e2d6..690bee8e1c4bc 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1287,7 +1287,7 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, } if (getLangOpts().C99 && InitStmt->get() != nullptr && - InitStmt->get()->getStmtClass() != Stmt::DeclStmtClass){ + InitStmt->get()->getStmtClass() != Stmt::DeclStmtClass) { // C2y only permits declaration in the first clause of an if condition, // so it makes sense to error out in other conditions. Diag(InitStmt->get()->getBeginLoc(), @@ -1298,7 +1298,7 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, } if (getLangOpts().C99 && InitStmt->get() != nullptr && - Cond.get().first != nullptr){ + Cond.get().first != nullptr) { // C2y only permits expression in the second clause of an if condition, // so it makes sense to error out in other conditions. Diag(Cond.get().first->getBeginLoc(), diag::err_expected_expression) >From 7108d370b462cf7b5db3b21c8fd30a9b7de9f0e6 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Wed, 20 May 2026 08:47:39 +0300 Subject: [PATCH 10/21] fix ci --- clang/lib/Parse/ParseStmt.cpp | 40 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 690bee8e1c4bc..38899baaf50a7 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1286,25 +1286,27 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, /*MissingOK=*/false); } - if (getLangOpts().C99 && InitStmt->get() != nullptr && - InitStmt->get()->getStmtClass() != Stmt::DeclStmtClass) { - // C2y only permits declaration in the first clause of an if condition, - // so it makes sense to error out in other conditions. - Diag(InitStmt->get()->getBeginLoc(), - diag::err_c2y_first_condition_clause_is_not_declaration) - << InitStmt->get()->getSourceRange(); - Cond = Sema::ConditionError(); - return true; - } - - if (getLangOpts().C99 && InitStmt->get() != nullptr && - Cond.get().first != nullptr) { - // C2y only permits expression in the second clause of an if condition, - // so it makes sense to error out in other conditions. - Diag(Cond.get().first->getBeginLoc(), diag::err_expected_expression) - << Cond.get().first->getSourceRange(); - Cond = Sema::ConditionError(); - return true; + if (getLangOpts().C99) { + if (InitStmt != nullptr && InitStmt->isUsable()) { + // handle the 2 clauses of declaration: (clause1; clause2) + if (InitStmt->get()->getStmtClass() != Stmt::DeclStmtClass) + // C2y only permits declaration in the first clause of an if condition, + // so it makes sense to error out in other conditions. + Diag(InitStmt->get()->getBeginLoc(), + diag::err_c2y_first_condition_clause_is_not_declaration) + << InitStmt->get()->getSourceRange(); + + if (Cond.get().first != nullptr) + // C2y only permits expression in the second clause of an if condition, + // so it makes sense to error out in other conditions. + Diag(Cond.get().first->getBeginLoc(), diag::err_expected_expression) + << Cond.get().first->getSourceRange(); + } else if (Cond.get().first != nullptr) + // handle: if (int decl = 0) {} + Diag(Cond.get().first->getBeginLoc(), + getLangOpts().C2y ? diag::warn_c2y_compat_init_statement + : diag::ext_c2y_init_statement) + << (CK == Sema::ConditionKind::Switch); } // Either the condition is valid or the rparen is present. >From aab7a00164a0c1e71e51d192618acc23f16f803d Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Wed, 20 May 2026 09:51:01 +0300 Subject: [PATCH 11/21] format --- 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 38899baaf50a7..2def5572593c2 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1293,7 +1293,7 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, // C2y only permits declaration in the first clause of an if condition, // so it makes sense to error out in other conditions. Diag(InitStmt->get()->getBeginLoc(), - diag::err_c2y_first_condition_clause_is_not_declaration) + diag::err_c2y_first_condition_clause_is_not_declaration) << InitStmt->get()->getSourceRange(); if (Cond.get().first != nullptr) >From f68e79f89338d9caec8ca20bc6c6ed18a363e46b Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Wed, 20 May 2026 18:31:56 +0300 Subject: [PATCH 12/21] Drop CXX from ParseCXXCondition --- clang/include/clang/Parse/Parser.h | 10 ++++------ clang/lib/Parse/ParseExprCXX.cpp | 15 ++++++++------- clang/lib/Parse/ParseStmt.cpp | 4 ++-- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index dc3dc8a4ae0e9..e836c23ef424a 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5039,12 +5039,10 @@ class Parser : public CodeCompletionHandler { /// appropriate moment for a 'for' loop. /// /// \returns The parsed condition. - Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt, - SourceLocation Loc, - Sema::ConditionKind CK, - bool MissingOK, - ForRangeInfo *FRI = nullptr, - bool EnterForConditionScope = false); + Sema::ConditionResult ParseCondition(StmtResult *InitStmt, SourceLocation Loc, + Sema::ConditionKind CK, bool MissingOK, + ForRangeInfo *FRI = nullptr, + bool EnterForConditionScope = false); DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context, ParsedAttributes &Attrs); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index d23c0ab1588d3..de36ef9b5b0be 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1865,10 +1865,11 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context, return DG; } -Sema::ConditionResult -Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, - Sema::ConditionKind CK, bool MissingOK, - ForRangeInfo *FRI, bool EnterForConditionScope) { +Sema::ConditionResult Parser::ParseCondition(StmtResult *InitStmt, + SourceLocation Loc, + Sema::ConditionKind CK, + bool MissingOK, ForRangeInfo *FRI, + bool EnterForConditionScope) { // Helper to ensure we always enter a continue/break scope if requested. struct ForConditionScopeRAII { Scope *S; @@ -1930,7 +1931,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, } ConsumeToken(); *InitStmt = Actions.ActOnNullStmt(SemiLoc); - return ParseCXXCondition(nullptr, Loc, CK, MissingOK); + return ParseCondition(nullptr, Loc, CK, MissingOK); } EnterExpressionEvaluationContext Eval( @@ -1948,7 +1949,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, WarnOnInit(); *InitStmt = Actions.ActOnExprStmt(Expr.get()); ConsumeToken(); - return ParseCXXCondition(nullptr, Loc, CK, MissingOK); + return ParseCondition(nullptr, Loc, CK, MissingOK); } return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK, @@ -1968,7 +1969,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, attrs, DeclSpecAttrs, /*RequireSemi=*/true); } *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd); - return ParseCXXCondition(nullptr, Loc, CK, MissingOK); + return ParseCondition(nullptr, Loc, CK, MissingOK); } case ConditionOrInitStatement::ForRangeDecl: { diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 2def5572593c2..a06df4734f5c9 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1264,7 +1264,7 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, T.consumeOpen(); SourceLocation Start = Tok.getLocation(); - Cond = ParseCXXCondition(InitStmt, Loc, CK, false); + Cond = ParseCondition(InitStmt, Loc, CK, false); // If the parser was confused by the condition and we don't have a ')', try to // recover by skipping ahead to a semi and bailing out. If condexp is @@ -2121,7 +2121,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc, ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); SourceLocation SecondPartStart = Tok.getLocation(); Sema::ConditionKind CK = Sema::ConditionKind::Boolean; - SecondPart = ParseCXXCondition( + SecondPart = ParseCondition( /*InitStmt=*/nullptr, ForLoc, CK, // FIXME: recovery if we don't see another semi! /*MissingOK=*/true, MightBeForRangeStmt ? &ForRangeInfo : nullptr, >From 37a3f35260961ca4780a6ec8ece8e46851c5f58d Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Wed, 20 May 2026 19:41:32 +0300 Subject: [PATCH 13/21] apply code review --- clang/lib/Parse/ParseStmt.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index a06df4734f5c9..09ff368388a77 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1286,19 +1286,17 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, /*MissingOK=*/false); } - if (getLangOpts().C99) { + if (!getLangOpts().CPlusPlus) { if (InitStmt != nullptr && InitStmt->isUsable()) { - // handle the 2 clauses of declaration: (clause1; clause2) - if (InitStmt->get()->getStmtClass() != Stmt::DeclStmtClass) - // C2y only permits declaration in the first clause of an if condition, - // so it makes sense to error out in other conditions. + // Handle the 2 clauses of declaration: (clause1; clause2). + if (!isa<DeclStmt>(InitStmt->get())) + // C2y only permits declaration in the first clause of an if condition. Diag(InitStmt->get()->getBeginLoc(), diag::err_c2y_first_condition_clause_is_not_declaration) << InitStmt->get()->getSourceRange(); if (Cond.get().first != nullptr) - // C2y only permits expression in the second clause of an if condition, - // so it makes sense to error out in other conditions. + // C2y only permits expression in the second clause of an if condition. Diag(Cond.get().first->getBeginLoc(), diag::err_expected_expression) << Cond.get().first->getSourceRange(); } else if (Cond.get().first != nullptr) >From 59acedbcce9ed6f00486e752d6b7a97de5352b01 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Wed, 20 May 2026 19:41:51 +0300 Subject: [PATCH 14/21] add more negative tests --- clang/test/C/C2y/n3267.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/test/C/C2y/n3267.c b/clang/test/C/C2y/n3267.c index 6cc2bdf4bc4a4..17e26561f10f8 100644 --- a/clang/test/C/C2y/n3267.c +++ b/clang/test/C/C2y/n3267.c @@ -39,6 +39,7 @@ bool negative_test_if() { if (true; bool y = true) return y; /* expected-error {{first clause in condition must be a declaration}} expected-error {{expected expression}} expected-warning {{expression result unused}}*/ + if (int x) {} // expected-error {{variable declaration in condition must have an initializer}} return false; } @@ -48,6 +49,9 @@ int negative_test_switch() { default: break; } + + switch (int x) {} // expected-error {{variable declaration in condition must have an initializer}} + switch (true; ) {} /* expected-error {{first clause in condition must be a declaration}} expected-error {{expected expression}} expected-warning {{expression result unused}} */ >From 825b89e8cc3dc79dd534455ba5795e0223984d26 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Wed, 20 May 2026 19:56:21 +0300 Subject: [PATCH 15/21] nit: comment style --- 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 09ff368388a77..50b53389e5889 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1300,7 +1300,7 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, Diag(Cond.get().first->getBeginLoc(), diag::err_expected_expression) << Cond.get().first->getSourceRange(); } else if (Cond.get().first != nullptr) - // handle: if (int decl = 0) {} + // Handle: if (int decl = 0) {}. Diag(Cond.get().first->getBeginLoc(), getLangOpts().C2y ? diag::warn_c2y_compat_init_statement : diag::ext_c2y_init_statement) >From b59adaadd225267a496ceeb90a2a4080d6ea003e Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Thu, 21 May 2026 07:06:58 +0300 Subject: [PATCH 16/21] add more positive tests --- clang/test/C/C2y/n3267.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/test/C/C2y/n3267.c b/clang/test/C/C2y/n3267.c index 17e26561f10f8..1a3f94724739e 100644 --- a/clang/test/C/C2y/n3267.c +++ b/clang/test/C/C2y/n3267.c @@ -7,6 +7,9 @@ bool test_if() { if ([[maybe_unused]] bool x = true) {} if (bool x [[maybe_unused]] = true) {} if ([[maybe_unused]] int x = 3; x > 0) {} + if (struct A { int x;} a = {.x = 1}; a.x) {} + if (int arr[] = {1,2,3}; arr[1]) {} + if (auto x = 1; x) {} return false; } @@ -22,6 +25,10 @@ int test_switch() { switch (int x [[maybe_unused]] = 1) {} switch ([[maybe_unused]] int x = 1) {} + switch (struct A { int x;} a = {.x = 1}; a.x) {} + switch (int arr[] = {1,2,3}; arr[1]) {} + switch (auto x = 1; x) {} + switch (int x = 1) { default: return y + x; >From 348bde9dda19fced4e88b3c031dd5d3c692db0a2 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Thu, 21 May 2026 07:15:19 +0300 Subject: [PATCH 17/21] fix name diverge from main --- clang/include/clang/Parse/Parser.h | 10 ++++------ clang/lib/Parse/ParseExprCXX.cpp | 10 +++++----- clang/lib/Parse/ParseOpenACC.cpp | 6 +++--- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index c6c492b4980af..476752fdd3b97 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5005,7 +5005,7 @@ class Parser : public CodeCompletionHandler { //===--------------------------------------------------------------------===// // C++ if/switch/while/for condition expression. - /// ParseCXXCondition - if/switch/while condition expression. + /// ParseCondition - if/switch/while condition expression. /// /// \verbatim /// condition: @@ -5036,11 +5036,9 @@ class Parser : public CodeCompletionHandler { /// returned. /// /// \returns The parsed condition. - Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt, - SourceLocation Loc, - Sema::ConditionKind CK, - bool MissingOK, - ForRangeInfo *FRI = nullptr); + Sema::ConditionResult ParseCondition(StmtResult *InitStmt, SourceLocation Loc, + Sema::ConditionKind CK, bool MissingOK, + ForRangeInfo *FRI = nullptr); DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context, ParsedAttributes &Attrs); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 8ca244d5f123b..03dd1683e2301 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1865,11 +1865,11 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context, return DG; } -Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, - SourceLocation Loc, - Sema::ConditionKind CK, - bool MissingOK, - ForRangeInfo *FRI) { +Sema::ConditionResult Parser::ParseCondition(StmtResult *InitStmt, + SourceLocation Loc, + Sema::ConditionKind CK, + bool MissingOK, + ForRangeInfo *FRI) { ParenBraceBracketBalancer BalancerRAIIObj(*this); PreferredType.enterCondition(Actions, Tok.getLocation()); diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index a95c5730a001c..760525659154c 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -656,9 +656,9 @@ Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) { ExprResult Parser::ParseOpenACCConditionExpr() { // FIXME: It isn't clear if the spec saying 'condition' means the same as - // it does in an if/while/etc (See ParseCXXCondition), however as it was - // written with Fortran/C in mind, we're going to assume it just means an - // 'expression evaluating to boolean'. + // it does in an if/while/etc (See ParseCondition), however as it was written + // with Fortran/C in mind, we're going to assume it just means an 'expression + // evaluating to boolean'. ExprResult ER = ParseExpression(); if (!ER.isUsable()) >From 83022276053da9124ac13e2fb0466654aa8fbe22 Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Fri, 22 May 2026 06:46:33 +0300 Subject: [PATCH 18/21] add support for `static_assert-decl` and `attribute-specifier-sequence` with respective warnings --- .../clang/Basic/DiagnosticParseKinds.td | 3 ++ clang/lib/Parse/ParseExprCXX.cpp | 32 ++++++++++++++++++- clang/lib/Parse/ParseStmt.cpp | 3 +- clang/test/C/C2y/n3267.c | 14 ++++++++ 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 092fe1ed5344d..4d00d87def455 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -169,6 +169,9 @@ def ext_c2y_generic_with_type_arg : Extension< def warn_c2y_compat_generic_with_type_arg : Warning< "passing a type argument as the first operand to '_Generic' is incompatible " "with C standards before C2y">, InGroup<CPre2yCompat>, DefaultIgnore; +def warn_c2y_empty_declaration_statement : Warning< + "empty declaration statement of '%select{if|switch}0' has no effect">, + InGroup<C2y>; def warn_c2y_compat_init_statement : Warning< "%select{if|switch}0 initialization statements are incompatible with " "C standards before C2y">, DefaultIgnore, InGroup<CPre2yCompat>; diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 03dd1683e2301..be680f1cdeb22 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1881,7 +1881,7 @@ Sema::ConditionResult Parser::ParseCondition(StmtResult *InitStmt, } ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + bool parsedAttrs = MaybeParseCXX11Attributes(attrs); const auto WarnOnInit = [this, &CK] { if (getLangOpts().CPlusPlus) @@ -1896,6 +1896,36 @@ Sema::ConditionResult Parser::ParseCondition(StmtResult *InitStmt, << (CK == Sema::ConditionKind::Switch); }; + if (!getLangOpts().CPlusPlus) { + if (isDeclarationStatement() && !isCXXSimpleDeclaration(false)) { + WarnOnInit(); + DeclGroupPtrTy DG; + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + ParsedAttributes DeclSpecAttrs(AttrFactory); + // C2y replaces the init-statement in C++17 to be a declaration instead. + DG = ParseDeclaration(DeclaratorContext::SelectionInit, DeclEnd, attrs, + DeclSpecAttrs); + *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd); + return ParseCondition(nullptr, Loc, CK, MissingOK); + } + + if (Tok.is(tok::semi) && parsedAttrs) { + // Parse if ([[...]]; true). + WarnOnInit(); + if (attrs.empty()) { + SourceLocation SemiLoc = Tok.getLocation(); + Diag(SemiLoc, diag::warn_c2y_empty_declaration_statement) + << (CK == Sema::ConditionKind::Switch) + << FixItHint::CreateRemoval(SemiLoc); + ConsumeToken(); + InitStmt = nullptr; + } else + *InitStmt = Actions.ActOnAttributedStmt( + attrs, Actions.ActOnNullStmt(ConsumeToken()).get()); + return ParseCondition(nullptr, Loc, CK, MissingOK); + } + } + // Determine what kind of thing we have. switch (isCXXConditionDeclarationOrInitStatement(InitStmt, FRI)) { case ConditionOrInitStatement::Expression: { diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 45366e1f4e508..2e3a0e027995b 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1289,7 +1289,8 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, if (!getLangOpts().CPlusPlus) { if (InitStmt != nullptr && InitStmt->isUsable()) { // Handle the 2 clauses of declaration: (clause1; clause2). - if (!isa<DeclStmt>(InitStmt->get())) + if (!isa<DeclStmt>(InitStmt->get()) && + !isa<AttributedStmt>(InitStmt->get())) // C2y only permits declaration in the first clause of an if condition. Diag(InitStmt->get()->getBeginLoc(), diag::err_c2y_first_condition_clause_is_not_declaration) diff --git a/clang/test/C/C2y/n3267.c b/clang/test/C/C2y/n3267.c index 1a3f94724739e..3b56060c99edc 100644 --- a/clang/test/C/C2y/n3267.c +++ b/clang/test/C/C2y/n3267.c @@ -10,6 +10,8 @@ bool test_if() { if (struct A { int x;} a = {.x = 1}; a.x) {} if (int arr[] = {1,2,3}; arr[1]) {} if (auto x = 1; x) {} + if (static_assert(true); true) {} + if ([[clang::assume(1 > 0)]]; true) {} return false; } @@ -28,6 +30,12 @@ int test_switch() { switch (struct A { int x;} a = {.x = 1}; a.x) {} switch (int arr[] = {1,2,3}; arr[1]) {} switch (auto x = 1; x) {} + switch (static_assert(true); 1) { + default: + } + switch ([[clang::assume(1 > 0)]]; 1) { + default: + } switch (int x = 1) { default: @@ -47,6 +55,7 @@ bool negative_test_if() { expected-error {{expected expression}} expected-warning {{expression result unused}}*/ if (int x) {} // expected-error {{variable declaration in condition must have an initializer}} + if ([[]]; true) {} // expected-warning {{empty declaration statement of 'if' has no effect}} return false; } @@ -62,6 +71,11 @@ int negative_test_switch() { switch (true; ) {} /* expected-error {{first clause in condition must be a declaration}} expected-error {{expected expression}} expected-warning {{expression result unused}} */ + + switch ([[]]; 1) { // expected-warning {{empty declaration statement of 'switch' has no effect}} + default: + } + switch (int x = 1; int y = x) { // expected-error {{expected expression}} default: return y; >From 89c0b905d39a3d2f2440a20d42c2c913dde210d0 Mon Sep 17 00:00:00 2001 From: Muhammad Bassiouni <[email protected]> Date: Fri, 22 May 2026 07:26:30 +0300 Subject: [PATCH 19/21] Update clang/lib/Parse/ParseExprCXX.cpp Co-authored-by: Timm Baeder <[email protected]> --- clang/lib/Parse/ParseExprCXX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index be680f1cdeb22..db2d1301f0cbe 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1881,7 +1881,7 @@ Sema::ConditionResult Parser::ParseCondition(StmtResult *InitStmt, } ParsedAttributes attrs(AttrFactory); - bool parsedAttrs = MaybeParseCXX11Attributes(attrs); + bool ParsedAttrs = MaybeParseCXX11Attributes(attrs); const auto WarnOnInit = [this, &CK] { if (getLangOpts().CPlusPlus) >From 17659bcc6c1fe1cc11a5c35f77ebd96a69272cbe Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Fri, 22 May 2026 07:58:00 +0300 Subject: [PATCH 20/21] fix ci --- clang/lib/Parse/ParseExprCXX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index db2d1301f0cbe..6aaec052daf7e 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1909,7 +1909,7 @@ Sema::ConditionResult Parser::ParseCondition(StmtResult *InitStmt, return ParseCondition(nullptr, Loc, CK, MissingOK); } - if (Tok.is(tok::semi) && parsedAttrs) { + if (Tok.is(tok::semi) && ParsedAttrs) { // Parse if ([[...]]; true). WarnOnInit(); if (attrs.empty()) { >From 79ba0d24c038795642ebe7dfbc58d7348171dbce Mon Sep 17 00:00:00 2001 From: bassiounix <[email protected]> Date: Fri, 22 May 2026 14:50:11 +0300 Subject: [PATCH 21/21] update backport mode --- clang/docs/LanguageExtensions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 33f07f86e1e23..b0cbeb54f2d55 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2014,7 +2014,7 @@ Octal literals prefixed with ``0o`` or ``0O`` C ``_Generic`` with a type operand (N3260) C2y C89, C++ ``++``/``--`` on ``_Complex`` value (N3259) C2y C89, C++ ``__COUNTER__`` (N3457) C2y C89, C++ -If declarations (N3356) C2y C99 +If declarations (N3356) C2y C89 ============================================= ================================ ============= ============= Builtin type aliases _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
