Skip to content

Commit 5b3ba26

Browse files
authored
[Clang] [Sema] Allow non-local/non-variable declarations in for loop (#129737)
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.
1 parent 4b454af commit 5b3ba26

File tree

4 files changed

+42
-12
lines changed

4 files changed

+42
-12
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ Bug Fixes in This Version
248248
(#GH125500).
249249
- Fixed clang crash when #embed data does not fit into an array
250250
(#GH128987).
251+
- Non-local variable and non-variable declarations in the first clause of a ``for`` loop in C are no longer incorrectly
252+
considered an error in C23 mode and are allowed as an extension in earlier language modes.
251253

252254
Bug Fixes to Compiler Builtins
253255
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10797,6 +10797,23 @@ def err_non_local_variable_decl_in_for : Error<
1079710797
"declaration of non-local variable in 'for' loop">;
1079810798
def err_non_variable_decl_in_for : Error<
1079910799
"non-variable declaration in 'for' loop">;
10800+
10801+
def ext_c23_non_local_variable_decl_in_for : Extension<
10802+
"declaration of non-local variable in 'for' loop is a C23 extension">,
10803+
InGroup<C23>;
10804+
10805+
def warn_c17_non_local_variable_decl_in_for : Warning<
10806+
"declaration of non-local variable in 'for' loop is incompatible with C standards before C23">,
10807+
DefaultIgnore, InGroup<CPre23Compat>;
10808+
10809+
def ext_c23_non_variable_decl_in_for : Extension<
10810+
"non-variable declaration in 'for' loop is a C23 extension">,
10811+
InGroup<C23>;
10812+
10813+
def warn_c17_non_variable_decl_in_for : Warning<
10814+
"non-variable declaration in 'for' loop is incompatible with C standards before C23">,
10815+
DefaultIgnore, InGroup<CPre23Compat>;
10816+
1080010817
def err_toomany_element_decls : Error<
1080110818
"only one element declaration is allowed">;
1080210819
def err_selector_element_not_lvalue : Error<

clang/lib/Sema/SemaStmt.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2269,10 +2269,11 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
22692269
for (auto *DI : DS->decls()) {
22702270
if (VarDecl *VD = dyn_cast<VarDecl>(DI)) {
22712271
VarDeclSeen = true;
2272-
if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) {
2273-
Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
2274-
DI->setInvalidDecl();
2275-
}
2272+
if (VD->isLocalVarDecl() && !VD->hasLocalStorage())
2273+
Diag(DI->getLocation(),
2274+
getLangOpts().C23
2275+
? diag::warn_c17_non_local_variable_decl_in_for
2276+
: diag::ext_c23_non_local_variable_decl_in_for);
22762277
} else if (!NonVarSeen) {
22772278
// Keep track of the first non-variable declaration we saw so that
22782279
// we can diagnose if we don't see any variable declarations. This
@@ -2284,7 +2285,9 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
22842285
// Diagnose if we saw a non-variable declaration but no variable
22852286
// declarations.
22862287
if (NonVarSeen && !VarDeclSeen)
2287-
Diag(NonVarSeen->getLocation(), diag::err_non_variable_decl_in_for);
2288+
Diag(NonVarSeen->getLocation(),
2289+
getLangOpts().C23 ? diag::warn_c17_non_variable_decl_in_for
2290+
: diag::ext_c23_non_variable_decl_in_for);
22882291
}
22892292
}
22902293

clang/test/Sema/for.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify %s
1+
// RUN: %clang_cc1 -fsyntax-only -verify=c11 -std=c11 -pedantic %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify=c23 -std=c23 -Wpre-c23-compat %s
23

34
// Check C99 6.8.5p3
45
void b1 (void) { for (void (*f) (void);;); }
5-
void b2 (void) { for (void f (void);;); } // expected-error {{non-variable declaration in 'for' loop}}
6-
void b3 (void) { for (static int f;;); } // expected-error {{declaration of non-local variable}}
7-
void b4 (void) { for (typedef int f;;); } // expected-error {{non-variable declaration in 'for' loop}}
6+
void b2 (void) { for (void f (void);;); } /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
7+
c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */
8+
void b3 (void) { for (static int f;;); } /* c11-warning {{declaration of non-local variable in 'for' loop is a C23 extension}}
9+
c23-warning {{declaration of non-local variable in 'for' loop is incompatible with C standards before C23}} */
10+
11+
void b4 (void) { for (typedef int f;;); } /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
12+
c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */
813
void b5 (void) { for (struct { int i; } s;;); }
914
void b6 (void) { for (enum { zero, ten = 10 } i;;); }
10-
void b7 (void) { for (struct s { int i; };;); } // expected-error {{non-variable declaration in 'for' loop}}
11-
void b8 (void) { for (static struct { int i; } s;;); } // expected-error {{declaration of non-local variable}}
15+
void b7 (void) { for (struct s { int i; };;); } /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
16+
c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */
17+
void b8 (void) { for (static struct { int i; } s;;); } /* c11-warning {{declaration of non-local variable in 'for' loop is a C23 extension}}
18+
c23-warning {{declaration of non-local variable in 'for' loop is incompatible with C standards before C23}} */
1219
void b9 (void) { for (struct { int i; } (*s)(struct { int j; } o) = 0;;); }
13-
void b10(void) { for (typedef struct { int i; } (*s)(struct { int j; });;); } // expected-error {{non-variable declaration in 'for' loop}}
20+
void b10(void) { for (typedef struct { int i; } (*s)(struct { int j; });;); } /* c11-warning {{non-variable declaration in 'for' loop is a C23 extension}}
21+
c23-warning {{non-variable declaration in 'for' loop is incompatible with C standards before C23}} */

0 commit comments

Comments
 (0)