[llvm-branch-commits] [clang] 2d2498e - No longer reject tag declarations in the clause-1 of a for loop.

Aaron Ballman via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Dec 18 05:00:43 PST 2020


Author: Aaron Ballman
Date: 2020-12-18T07:56:17-05:00
New Revision: 2d2498ec6c42b12eae873257e6ddce3333fe8348

URL: https://github.com/llvm/llvm-project/commit/2d2498ec6c42b12eae873257e6ddce3333fe8348
DIFF: https://github.com/llvm/llvm-project/commit/2d2498ec6c42b12eae873257e6ddce3333fe8348.diff

LOG: 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.

Added: 
    

Modified: 
    clang/lib/Sema/SemaStmt.cpp
    clang/test/Sema/for.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index d89dfaf78a9c..8d0ebe7e2409 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<VarDecl>(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<VarDecl>(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 b998f4b07cf0..d0c2f7f21a96 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}}


        


More information about the llvm-branch-commits mailing list