From 2d2498ec6c42b12eae873257e6ddce3333fe8348 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Fri, 18 Dec 2020 07:53:39 -0500 Subject: [PATCH] No longer reject tag declarations in the clause-1 of a for loop. We currently reject this valid C construct by claiming it declares a non-local variable: for (struct { int i; } s={0}; s.i != 0; s.i--) ; We expected all declaration in the clause-1 declaration statement to be a local VarDecl, but there can be other declarations involved such as a tag declaration. This fixes PR35757. --- clang/lib/Sema/SemaStmt.cpp | 24 ++++++++++++++++++------ clang/test/Sema/for.c | 10 ++++++++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index d89dfaf..8d0ebe7 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -1822,15 +1822,27 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, // C99 6.8.5p3: The declaration part of a 'for' statement shall only // declare identifiers for objects having storage class 'auto' or // 'register'. + const Decl *NonVarSeen = nullptr; + bool VarDeclSeen = false; for (auto *DI : DS->decls()) { - VarDecl *VD = dyn_cast(DI); - if (VD && VD->isLocalVarDecl() && !VD->hasLocalStorage()) - VD = nullptr; - if (!VD) { - Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for); - DI->setInvalidDecl(); + if (VarDecl *VD = dyn_cast(DI)) { + VarDeclSeen = true; + if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) { + Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for); + DI->setInvalidDecl(); + } + } 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 + // covers a case like declaring a typedef, function, or structure + // type rather than a variable. + NonVarSeen = DI; } } + // 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); } } diff --git a/clang/test/Sema/for.c b/clang/test/Sema/for.c index b998f4b..d0c2f7f 100644 --- a/clang/test/Sema/for.c +++ b/clang/test/Sema/for.c @@ -2,6 +2,12 @@ // Check C99 6.8.5p3 void b1 (void) { for (void (*f) (void);;); } -void b2 (void) { for (void f (void);;); } // expected-error {{declaration of non-local variable}} +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 {{declaration of non-local variable}} +void b4 (void) { for (typedef int f;;); } // expected-error {{non-variable declaration in 'for' loop}} +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 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}} -- 2.7.4