Repository: llvm/llvm-project
Pull request #129737: [Clang] [Sema] Allow non-local/non-variable declarations in for loop
Author: login: Sirraide
Labels: name: clang
description: Clang issues not falling into any other category
name: c23
name: clang:frontend
description: Language frontend issues, e.g. anything involving "Sema"
Created: 2025-03-04T16:40:00Z | Merged: 2025-03-06T01:03:22Z

Currently, we error on non-variable or non-local variable declarations in `for` loops such as `for (struct S {}; 0; ) {}`. However, this is valid in C23, so this patch changes the error to a compatibilty warning and also allows this as an extension in earlier language modes. This also matches GCC’s behaviour.


Diff:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 35efa2ca4aa93..7f085d9ac04a1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -248,6 +248,8 @@ Bug Fixes in This Version
   (#GH125500).
 - Fixed clang crash when #embed data does not fit into an array
   (#GH128987).
+- Non-local variable and non-variable declarations in the first clause of a ``for`` loop in C are no longer incorrectly
+  considered an error in C23 mode and are allowed as an extension in earlier language modes.
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0b121c04cd3c0..ed2da2b355e11 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10797,6 +10797,23 @@ def err_non_local_variable_decl_in_for : Error<
   "declaration of non-local variable in 'for' loop">;
 def err_non_variable_decl_in_for : Error<
   "non-variable declaration in 'for' loop">;
+
+def ext_c23_non_local_variable_decl_in_for : Extension<
+  "declaration of non-local variable in 'for' loop is a C23 extension">,
+  InGroup<C23>;
+
+def warn_c17_non_local_variable_decl_in_for : Warning<
+  "declaration of non-local variable in 'for' loop is incompatible with C standards before C23">,
+  DefaultIgnore, InGroup<CPre23Compat>;
+
+def ext_c23_non_variable_decl_in_for : Extension<
+  "non-variable declaration in 'for' loop is a C23 extension">,
+  InGroup<C23>;
+
+def warn_c17_non_variable_decl_in_for : Warning<
+  "non-variable declaration in 'for' loop is incompatible with C standards before C23">,
+  DefaultIgnore, InGroup<CPre23Compat>;
+
 def err_toomany_element_decls : Error<
   "only one element declaration is allowed">;
 def err_selector_element_not_lvalue : Error<
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index d0b713f074c33..0a193b5299bcc 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2269,10 +2269,11 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
       for (auto *DI : DS->decls()) {
         if (VarDecl *VD = dyn_cast<VarDecl>(DI)) {
           VarDeclSeen = true;
-          if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) {
-            Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
-            DI->setInvalidDecl();
-          }
+          if (VD->isLocalVarDecl() && !VD->hasLocalStorage())
+            Diag(DI->getLocation(),
+                 getLangOpts().C23
+                     ? diag::warn_c17_non_local_variable_decl_in_for
+                     : diag::ext_c23_non_local_variable_decl_in_for);
         } else if (!NonVarSeen) {
           // Keep track of the first non-variable declaration we saw so that
           // we can diagnose if we don't see any variable declarations. This
@@ -2284,7 +2285,9 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
       // Diagnose if we saw a non-variable declaration but no variable
       // declarations.
       if (NonVarSeen && !VarDeclSeen)
-        Diag(NonVarSeen->getLocation(), diag::err_non_variable_decl_in_for);
+        Diag(NonVarSeen->getLocation(),
+             getLangOpts().C23 ? diag::warn_c17_non_variable_decl_in_for
+                               : diag::ext_c23_non_variable_decl_in_for);
     }
   }
 
diff --git a/clang/test/Sema/for.c b/clang/test/Sema/for.c
index d0c2f7f21a960..c21ef62247037 100644
--- a/clang/test/Sema/for.c
+++ b/clang/test/Sema/for.c
@@ -1,13 +1,21 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c11 -std=c11 -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c23 -std=c23 -Wpre-c23-compat %s
 
 // Check C99 6.8.5p3
 void b1 (void) { for (void (*f) (void);;); }
-void b2 (void) { for (void f (void);;); }   // expected-error {{non-variable declaration in 'for' loop}}
-void b3 (void) { for (static int f;;); }    // expected-error {{declaration of non-local variable}}
-void b4 (void) { for (typedef int f;;); }   // expected-error {{non-variable declaration in 'for' loop}}
+void b2 (void) { for (void f (void);;); }   /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
+                                               c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */
+void b3 (void) { for (static int f;;); }    /* c11-warning {{declaration of non-local variable in 'for' loop is a C23 extension}}
+                                               c23-warning {{declaration of non-local variable in 'for' loop is incompatible with C standards before C23}} */
+
+void b4 (void) { for (typedef int f;;); }   /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
+                                               c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */
 void b5 (void) { for (struct { int i; } s;;); }
 void b6 (void) { for (enum { zero, ten = 10 } i;;); }
-void b7 (void) { for (struct s { int i; };;); } // expected-error {{non-variable declaration in 'for' loop}}
-void b8 (void) { for (static struct { int i; } s;;); } // expected-error {{declaration of non-local variable}}
+void b7 (void) { for (struct s { int i; };;); } /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
+                                                   c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */
+void b8 (void) { for (static struct { int i; } s;;); } /* c11-warning {{declaration of non-local variable in 'for' loop is a C23 extension}}
+                                                          c23-warning {{declaration of non-local variable in 'for' loop is incompatible with C standards before C23}} */
 void b9 (void) { for (struct { int i; } (*s)(struct { int j; } o) = 0;;); }
-void b10(void) { for (typedef struct { int i; } (*s)(struct { int j; });;); } // expected-error {{non-variable declaration in 'for' loop}}
+void b10(void) { for (typedef struct { int i; } (*s)(struct { int j; });;); } /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
+                                                                                 c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */


Reviews:
user: login: Fznamznon
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T17:11:48Z
user: login: Sirraide
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-04T17:14:59Z
user: login: AaronBallman
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-04T21:32:02Z
user: login: cor3ntin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T08:14:55Z
user: login: Sirraide
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T19:05:31Z
user: login: AaronBallman
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-05T19:23:25Z
user: login: AaronBallman
body: LGTM
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-05T19:23:57Z
user: login: shafik
body: Should this have updated: https://clang.llvm.org/c_status.html

Also it would have been nice to mention the paper number in the release notes, I am assuming there was a paper? 

CC @AaronBallman 
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-07T01:54:31Z
user: login: shafik
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-07T01:55:46Z
user: login: shafik
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-07T02:03:13Z
user: login: Sirraide
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T13:48:07Z
user: login: Sirraide
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T13:50:10Z
user: login: shafik
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-07T15:38:41Z
user: login: Sirraide
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T15:41:31Z

Review comments:
diff_hunk: @@ -237,6 +237,8 @@ Bug Fixes in This Version
   when it can affect template argument deduction (#GH122306).
 - Fix crash on code completion of function calls involving partial order of function templates
   (#GH125500).
+- Non-local variable and non-variable declarations in the first clause of a ``for`` loop in C are no longer erroneously
+  considered an error in C23 mode and are allowed as an extension in earlier language modes.
path: clang/docs/ReleaseNotes.rst
user: login: Fznamznon
body: "_erroneously_ considered an error" kind of sounds tautological, since we're under bug fix section I think "are no longer considered an error" is enough. You may ignore this though, since I'm not an expert in English.
created_at: 2025-03-04T17:01:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -10794,6 +10794,23 @@ def err_non_local_variable_decl_in_for : Error<
   "declaration of non-local variable in 'for' loop">;
 def err_non_variable_decl_in_for : Error<
   "non-variable declaration in 'for' loop">;
+
+def ext_c23_non_local_variable_decl_in_for : Extension<
path: clang/include/clang/Basic/DiagnosticSemaKinds.td
user: login: Fznamznon
body: I wonder if we're missing some feature marked as supported on https://clang.llvm.org/c_status.html ? @AaronBallman 
created_at: 2025-03-04T17:02:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -237,6 +237,8 @@ Bug Fixes in This Version
   when it can affect template argument deduction (#GH122306).
 - Fix crash on code completion of function calls involving partial order of function templates
   (#GH125500).
+- Non-local variable and non-variable declarations in the first clause of a ``for`` loop in C are no longer erroneously
+  considered an error in C23 mode and are allowed as an extension in earlier language modes.
path: clang/docs/ReleaseNotes.rst
user: login: Sirraide
body: Well, I figured that without the ‘erroneously’ it might also be interpreted as the semantics of the language simply having changed rather than communicating that we were just wrong about this, but I don’t think that distinction matters too much, and, yeah, the fact that it’s listed as a bug fix is probably enough to communicate that it’s the latter, so I’ll just remove it.
created_at: 2025-03-04T17:14:59Z
author_association: MEMBER
diff_hunk: @@ -10794,6 +10794,23 @@ def err_non_local_variable_decl_in_for : Error<
   "declaration of non-local variable in 'for' loop">;
 def err_non_variable_decl_in_for : Error<
   "non-variable declaration in 'for' loop">;
+
+def ext_c23_non_local_variable_decl_in_for : Extension<
path: clang/include/clang/Basic/DiagnosticSemaKinds.td
user: login: AaronBallman
body: This change happened sometime between N3047 and N3096, so it was a national body comment. It turns out it was GB-125 (from https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3067.doc), which was addressed by section 4.3 in https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3078.htm according to https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3091.doc

So no need to track it on the status page, it wasn't really a feature paper but a cleanup.
created_at: 2025-03-04T21:29:13Z
author_association: COLLABORATOR
diff_hunk: @@ -10794,6 +10794,23 @@ def err_non_local_variable_decl_in_for : Error<
   "declaration of non-local variable in 'for' loop">;
 def err_non_variable_decl_in_for : Error<
   "non-variable declaration in 'for' loop">;
+
+def ext_c23_non_local_variable_decl_in_for : Extension<
path: clang/include/clang/Basic/DiagnosticSemaKinds.td
user: login: AaronBallman
body: You should remove the error diagnostics because they're no longer used.
created_at: 2025-03-04T21:31:13Z
author_association: COLLABORATOR
diff_hunk: @@ -237,6 +237,8 @@ Bug Fixes in This Version
   when it can affect template argument deduction (#GH122306).
 - Fix crash on code completion of function calls involving partial order of function templates
   (#GH125500).
+- Non-local variable and non-variable declarations in the first clause of a ``for`` loop in C are no longer erroneously
+  considered an error in C23 mode and are allowed as an extension in earlier language modes.
path: clang/docs/ReleaseNotes.rst
user: login: cor3ntin
body: incorrectly
created_at: 2025-03-05T08:14:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -10794,6 +10794,23 @@ def err_non_local_variable_decl_in_for : Error<
   "declaration of non-local variable in 'for' loop">;
 def err_non_variable_decl_in_for : Error<
   "non-variable declaration in 'for' loop">;
+
+def ext_c23_non_local_variable_decl_in_for : Extension<
path: clang/include/clang/Basic/DiagnosticSemaKinds.td
user: login: Sirraide
body: > You should remove the error diagnostics because they're no longer used.

Well, they *are* still used for C++ range-based `for` loops and for whatever an `ObjCForCollectionStmt` is.
created_at: 2025-03-05T19:05:31Z
author_association: MEMBER
diff_hunk: @@ -10794,6 +10794,23 @@ def err_non_local_variable_decl_in_for : Error<
   "declaration of non-local variable in 'for' loop">;
 def err_non_variable_decl_in_for : Error<
   "non-variable declaration in 'for' loop">;
+
+def ext_c23_non_local_variable_decl_in_for : Extension<
path: clang/include/clang/Basic/DiagnosticSemaKinds.td
user: login: AaronBallman
body: Oh good call, I missed that!
created_at: 2025-03-05T19:23:24Z
author_association: COLLABORATOR
diff_hunk: @@ -2269,10 +2269,11 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
       for (auto *DI : DS->decls()) {
         if (VarDecl *VD = dyn_cast<VarDecl>(DI)) {
           VarDeclSeen = true;
-          if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) {
-            Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
-            DI->setInvalidDecl();
-          }
+          if (VD->isLocalVarDecl() && !VD->hasLocalStorage())
path: clang/lib/Sema/SemaStmt.cpp
user: login: shafik
body: I am a big fan of quoting the section of the standard that allows various features. This allows folks in the future to know where to look to better understand the code.
created_at: 2025-03-07T01:55:44Z
author_association: COLLABORATOR
diff_hunk: @@ -1,13 +1,21 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c11 -std=c11 -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c23 -std=c23 -Wpre-c23-compat %s
 
 // Check C99 6.8.5p3
 void b1 (void) { for (void (*f) (void);;); }
-void b2 (void) { for (void f (void);;); }   // expected-error {{non-variable declaration in 'for' loop}}
-void b3 (void) { for (static int f;;); }    // expected-error {{declaration of non-local variable}}
-void b4 (void) { for (typedef int f;;); }   // expected-error {{non-variable declaration in 'for' loop}}
+void b2 (void) { for (void f (void);;); }   /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
path: clang/test/Sema/for.c
user: login: shafik
body: I think these test should have show the non-local variables being used within the loops as well. Otherwise the tests are not fully testing the functionality and are not fully protecting against regressions.


created_at: 2025-03-07T02:03:09Z
author_association: COLLABORATOR
diff_hunk: @@ -2269,10 +2269,11 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
       for (auto *DI : DS->decls()) {
         if (VarDecl *VD = dyn_cast<VarDecl>(DI)) {
           VarDeclSeen = true;
-          if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) {
-            Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
-            DI->setInvalidDecl();
-          }
+          if (VD->isLocalVarDecl() && !VD->hasLocalStorage())
path: clang/lib/Sema/SemaStmt.cpp
user: login: Sirraide
body: There is a C99 quote further up above on line 2264; we could add a comment that mentions that this changed at some point though. Something like ‘C23 has no such restriction’ maybe?
created_at: 2025-03-07T13:48:07Z
author_association: MEMBER
diff_hunk: @@ -1,13 +1,21 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c11 -std=c11 -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c23 -std=c23 -Wpre-c23-compat %s
 
 // Check C99 6.8.5p3
 void b1 (void) { for (void (*f) (void);;); }
-void b2 (void) { for (void f (void);;); }   // expected-error {{non-variable declaration in 'for' loop}}
-void b3 (void) { for (static int f;;); }    // expected-error {{declaration of non-local variable}}
-void b4 (void) { for (typedef int f;;); }   // expected-error {{non-variable declaration in 'for' loop}}
+void b2 (void) { for (void f (void);;); }   /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
path: clang/test/Sema/for.c
user: login: Sirraide
body: I mean, I can reference them in the loop condition I suppose.
created_at: 2025-03-07T13:50:10Z
author_association: MEMBER
diff_hunk: @@ -1,13 +1,21 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c11 -std=c11 -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c23 -std=c23 -Wpre-c23-compat %s
 
 // Check C99 6.8.5p3
 void b1 (void) { for (void (*f) (void);;); }
-void b2 (void) { for (void f (void);;); }   // expected-error {{non-variable declaration in 'for' loop}}
-void b3 (void) { for (static int f;;); }    // expected-error {{declaration of non-local variable}}
-void b4 (void) { for (typedef int f;;); }   // expected-error {{non-variable declaration in 'for' loop}}
+void b2 (void) { for (void f (void);;); }   /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
path: clang/test/Sema/for.c
user: login: shafik
body: Apologies for the drive by after commit review but I really would like to see that. Having spent some time digging into regression the past few months a main pattern is lack of testing and so I am trying to push asking for more in the testing arena.
created_at: 2025-03-07T15:38:41Z
author_association: COLLABORATOR
diff_hunk: @@ -1,13 +1,21 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c11 -std=c11 -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c23 -std=c23 -Wpre-c23-compat %s
 
 // Check C99 6.8.5p3
 void b1 (void) { for (void (*f) (void);;); }
-void b2 (void) { for (void f (void);;); }   // expected-error {{non-variable declaration in 'for' loop}}
-void b3 (void) { for (static int f;;); }    // expected-error {{declaration of non-local variable}}
-void b4 (void) { for (typedef int f;;); }   // expected-error {{non-variable declaration in 'for' loop}}
+void b2 (void) { for (void f (void);;); }   /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
path: clang/test/Sema/for.c
user: login: Sirraide
body: Makes sense; I’m a bit busy at the moment but I should be able to do that next week considering that it shouldn’t take too long.
created_at: 2025-03-07T15:41:31Z
author_association: MEMBER

PR comments:
user: login: llvmbot
created_at: 2025-03-04T16:40:38Z
body: 
<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (Sirraide)

<details>
<summary>Changes</summary>

Currently, we error on non-variable or non-local variable declarations in `for` loops such as `for (struct S {}; 0; ) {}`. However, this is valid in C23, so this patch changes the error to a compatibilty warning and also allows this as an extension in earlier language modes. This also matches GCC’s behaviour.

---
Full diff: https://github.com/llvm/llvm-project/pull/129737.diff


4 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+2) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+17) 
- (modified) clang/lib/Sema/SemaStmt.cpp (+8-5) 
- (modified) clang/test/Sema/for.c (+15-7) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 97b8e32f03b57..cf205e7064aa8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -237,6 +237,8 @@ Bug Fixes in This Version
   when it can affect template argument deduction (#GH122306).
 - Fix crash on code completion of function calls involving partial order of function templates
   (#GH125500).
+- Non-local variable and non-variable declarations in the first clause of a ``for`` loop in C are no longer erroneously
+  considered an error in C23 mode and are allowed as an extension in earlier language modes.
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d89648a8a2e83..c87ef62310cb9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10794,6 +10794,23 @@ def err_non_local_variable_decl_in_for : Error<
   "declaration of non-local variable in 'for' loop">;
 def err_non_variable_decl_in_for : Error<
   "non-variable declaration in 'for' loop">;
+
+def ext_c23_non_local_variable_decl_in_for : Extension<
+  "declaration of non-local variable in 'for' loop is a C23 extension">,
+  InGroup<C23>;
+
+def warn_c17_non_local_variable_decl_in_for : Warning<
+  "declaration of non-local variable in 'for' loop is incompatible with C standards before C23">,
+  DefaultIgnore, InGroup<CPre23Compat>;
+
+def ext_c23_non_variable_decl_in_for : Extension<
+  "non-variable declaration in 'for' loop is a C23 extension">,
+  InGroup<C23>;
+
+def warn_c17_non_variable_decl_in_for : Warning<
+  "non-variable declaration in 'for' loop is incompatible with C standards before C23">,
+  DefaultIgnore, InGroup<CPre23Compat>;
+
 def err_toomany_element_decls : Error<
   "only one element declaration is allowed">;
 def err_selector_element_not_lvalue : Error<
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index d0b713f074c33..0a193b5299bcc 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2269,10 +2269,11 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
       for (auto *DI : DS->decls()) {
         if (VarDecl *VD = dyn_cast<VarDecl>(DI)) {
           VarDeclSeen = true;
-          if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) {
-            Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
-            DI->setInvalidDecl();
-          }
+          if (VD->isLocalVarDecl() && !VD->hasLocalStorage())
+            Diag(DI->getLocation(),
+                 getLangOpts().C23
+                     ? diag::warn_c17_non_local_variable_decl_in_for
+                     : diag::ext_c23_non_local_variable_decl_in_for);
         } else if (!NonVarSeen) {
           // Keep track of the first non-variable declaration we saw so that
           // we can diagnose if we don't see any variable declarations. This
@@ -2284,7 +2285,9 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
       // Diagnose if we saw a non-variable declaration but no variable
       // declarations.
       if (NonVarSeen && !VarDeclSeen)
-        Diag(NonVarSeen->getLocation(), diag::err_non_variable_decl_in_for);
+        Diag(NonVarSeen->getLocation(),
+             getLangOpts().C23 ? diag::warn_c17_non_variable_decl_in_for
+                               : diag::ext_c23_non_variable_decl_in_for);
     }
   }
 
diff --git a/clang/test/Sema/for.c b/clang/test/Sema/for.c
index d0c2f7f21a960..c21ef62247037 100644
--- a/clang/test/Sema/for.c
+++ b/clang/test/Sema/for.c
@@ -1,13 +1,21 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c11 -std=c11 -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c23 -std=c23 -Wpre-c23-compat %s
 
 // Check C99 6.8.5p3
 void b1 (void) { for (void (*f) (void);;); }
-void b2 (void) { for (void f (void);;); }   // expected-error {{non-variable declaration in 'for' loop}}
-void b3 (void) { for (static int f;;); }    // expected-error {{declaration of non-local variable}}
-void b4 (void) { for (typedef int f;;); }   // expected-error {{non-variable declaration in 'for' loop}}
+void b2 (void) { for (void f (void);;); }   /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
+                                               c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */
+void b3 (void) { for (static int f;;); }    /* c11-warning {{declaration of non-local variable in 'for' loop is a C23 extension}}
+                                               c23-warning {{declaration of non-local variable in 'for' loop is incompatible with C standards before C23}} */
+
+void b4 (void) { for (typedef int f;;); }   /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
+                                               c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */
 void b5 (void) { for (struct { int i; } s;;); }
 void b6 (void) { for (enum { zero, ten = 10 } i;;); }
-void b7 (void) { for (struct s { int i; };;); } // expected-error {{non-variable declaration in 'for' loop}}
-void b8 (void) { for (static struct { int i; } s;;); } // expected-error {{declaration of non-local variable}}
+void b7 (void) { for (struct s { int i; };;); } /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
+                                                   c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */
+void b8 (void) { for (static struct { int i; } s;;); } /* c11-warning {{declaration of non-local variable in 'for' loop is a C23 extension}}
+                                                          c23-warning {{declaration of non-local variable in 'for' loop is incompatible with C standards before C23}} */
 void b9 (void) { for (struct { int i; } (*s)(struct { int j; } o) = 0;;); }
-void b10(void) { for (typedef struct { int i; } (*s)(struct { int j; });;); } // expected-error {{non-variable declaration in 'for' loop}}
+void b10(void) { for (typedef struct { int i; } (*s)(struct { int j; });;); } /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
+                                                                                 c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */

``````````

</details>

author_association: MEMBER
user: login: Sirraide
created_at: 2025-03-07T13:46:50Z
body: > Should this have updated: https://clang.llvm.org/c_status.html

Not according to Aaron: https://github.com/llvm/llvm-project/pull/129737#discussion_r1980260552


author_association: MEMBER
user: login: shafik
created_at: 2025-03-07T15:36:40Z
body: > > Should this have updated: https://clang.llvm.org/c_status.html
> 
> Not according to Aaron: [#129737 (comment)](https://github.com/llvm/llvm-project/pull/129737#discussion_r1980260552)

Oh wow, my bad, I missed that 😬
author_association: COLLABORATOR