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

Reply via email to