* c-decl.c (check_for_loop_decls): New function.
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 18 Nov 2000 23:18:36 +0000 (23:18 +0000)
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 18 Nov 2000 23:18:36 +0000 (23:18 +0000)
* c-parse.in (for_init_stmt): New.
(select_or_iter_stmt): Use for_init_stmt.
* c-tree.h (check_for_loop_decls): New declaration.

testsuite:
* gcc.dg/c90-fordecl-1.c, gcc.dg/c99-fordecl-1.c,
gcc.dg/c99-fordecl-2.c: New tests.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@37549 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-decl.c
gcc/c-parse.in
gcc/c-tree.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/c90-fordecl-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-fordecl-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-fordecl-2.c [new file with mode: 0644]

index 9e5850e..e80a489 100644 (file)
@@ -1,3 +1,10 @@
+2000-11-18  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       * c-decl.c (check_for_loop_decls): New function.
+       * c-parse.in (for_init_stmt): New.
+       (select_or_iter_stmt): Use for_init_stmt.
+       * c-tree.h (check_for_loop_decls): New declaration.
+
 2000-11-18  Neil Booth  <neilb@earthling.net>
 
        * cppinit.c: Update comments.
index 8d66b4e..d97419d 100644 (file)
@@ -6924,6 +6924,55 @@ c_expand_body (fndecl, nested_p)
       
 }
 \f
+/* Check the declarations given in a for-loop for satisfying the C99
+   constraints.  */
+void
+check_for_loop_decls ()
+{
+  tree t;
+
+  if (!flag_isoc99)
+    {
+      /* If we get here, declarations have been used in a for loop without
+        the C99 for loop scope.  This doesn't make much sense, so don't
+        allow it.  */
+      error ("`for' loop initial declaration used outside C99 mode");
+      return;
+    }
+  /* C99 subclause 6.8.5 paragraph 3:
+
+       [#3]  The  declaration  part  of  a for statement shall only
+       declare identifiers for objects having storage class auto or
+       register.
+
+     It isn't clear whether, in this sentence, "identifiers" binds to
+     "shall only declare" or to "objects" - that is, whether all identifiers
+     declared must be identifiers for objects, or whether the restriction
+     only applies to those that are.  (A question on this in comp.std.c
+     in November 2000 received no answer.)  We implement the strictest
+     interpretation, to avoid creating an extension which later causes
+     problems.  */
+
+  for (t = gettags (); t; t = TREE_CHAIN (t))
+    {
+      if (TREE_PURPOSE (t) != 0)
+       error ("`%s %s' declared in `for' loop initial declaration",
+              (TREE_CODE (TREE_VALUE (t)) == RECORD_TYPE ? "struct"
+               : TREE_CODE (TREE_VALUE (t)) == UNION_TYPE ? "union"
+               : "enum"),
+              IDENTIFIER_POINTER (TREE_PURPOSE (t)));
+    }
+  for (t = getdecls (); t; t = TREE_CHAIN (t))
+    {
+      if (TREE_CODE (t) != VAR_DECL && DECL_NAME (t))
+       error_with_decl (t, "declaration of non-variable `%s' in `for' loop initial declaration");
+      else if (TREE_STATIC (t))
+       error_with_decl (t, "declaration of static variable `%s' in `for' loop initial declaration");
+      else if (DECL_EXTERNAL (t))
+       error_with_decl (t, "declaration of `extern' variable `%s' in `for' loop initial declaration");
+    }
+}
+\f
 /* Save and restore the variables in this file and elsewhere
    that keep track of the progress of compilation of the current function.
    Used for nested functions.  */
index ae47466..517b488 100644 (file)
@@ -1868,19 +1868,18 @@ select_or_iter_stmt:
        | do_stmt_start error
                { }
        | FOR
-         '(' xexpr ';'
-               { stmt_count++;
-                 $3 = build_stmt (EXPR_STMT, $3); 
-                 $<ttype>$ = build_stmt (FOR_STMT, $3, NULL_TREE,
+               { $<ttype>$ = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
                                          NULL_TREE, NULL_TREE);
-                 add_stmt ($<ttype>$);
-               }
+                 add_stmt ($<ttype>$); } 
+         '(' for_init_stmt
+               { stmt_count++;
+                 RECHAIN_STMTS ($<ttype>2, FOR_INIT_STMT ($<ttype>2)); }
          xexpr ';'
-                { FOR_COND ($<ttype>5) = $6; }
+                { FOR_COND ($<ttype>2) = $6; }
          xexpr ')'
-               { FOR_EXPR ($<ttype>5) = $9; }
+               { FOR_EXPR ($<ttype>2) = $9; }
          c99_block_lineno_labeled_stmt
-                { RECHAIN_STMTS ($<ttype>5, FOR_BODY ($<ttype>5)); }
+                { RECHAIN_STMTS ($<ttype>2, FOR_BODY ($<ttype>2)); }
        | SWITCH '(' expr ')'
                { stmt_count++;
                  $<ttype>$ = c_start_case ($3); }
@@ -1888,6 +1887,13 @@ select_or_iter_stmt:
                 { c_finish_case (); }
        ;
 
+for_init_stmt:
+         xexpr ';'
+               { add_stmt (build_stmt (EXPR_STMT, $1)); } 
+       | decl
+               { check_for_loop_decls (); }
+       ;
+
 /* Parse a single real statement, not including any labels.  */
 stmt:
          compstmt
index efd5083..669c89b 100644 (file)
@@ -170,6 +170,7 @@ extern tree build_enumerator                    PARAMS ((tree, tree));
                          ((VOLATILE_P) ? TYPE_QUAL_VOLATILE : 0))
 extern int  c_decode_option                     PARAMS ((int, char **));
 extern void c_mark_varargs                      PARAMS ((void));
+extern void check_for_loop_decls                PARAMS ((void));
 extern tree check_identifier                    PARAMS ((tree, tree));
 extern void clear_parm_order                    PARAMS ((void));
 extern tree combine_parm_decls                  PARAMS ((tree, tree, int));
index 6b0dcaa..78eb81f 100644 (file)
@@ -1,3 +1,8 @@
+2000-11-18  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       * gcc.dg/c90-fordecl-1.c, gcc.dg/c99-fordecl-1.c,
+       gcc.dg/c99-fordecl-2.c: New tests.
+
 2000-11-18  Richard Henderson  <rth@redhat.com>
 
        * gcc.c-torture/execute/zerolen-1.c: Rename from 20001115-1.c.
diff --git a/gcc/testsuite/gcc.dg/c90-fordecl-1.c b/gcc/testsuite/gcc.dg/c90-fordecl-1.c
new file mode 100644 (file)
index 0000000..8e48dd6
--- /dev/null
@@ -0,0 +1,13 @@
+/* Test for C99 declarations in for loops - rejection in C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+void
+foo (void)
+{
+  int j = 0;
+  for (int i = 1; i <= 10; i++) /* { dg-bogus "warning" "warning in place of error" } */
+    j += i;
+  /* { dg-error "parse|decl" "declaration in for loop" { target *-*-* } 10 } */
+}
diff --git a/gcc/testsuite/gcc.dg/c99-fordecl-1.c b/gcc/testsuite/gcc.dg/c99-fordecl-1.c
new file mode 100644 (file)
index 0000000..faaab1e
--- /dev/null
@@ -0,0 +1,35 @@
+/* Test for C99 declarations in for loops.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do run } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+extern void abort (void);
+extern void exit (int);
+
+int
+main (void)
+{
+  int j = 0;
+  int i = -1;
+  for (int i = 1; i <= 10; i++)
+    j += i;
+  if (j != 55)
+    abort ();
+  if (i != -1)
+    abort ();
+  j = 0;
+  for (auto int i = 1; i <= 10; i++)
+    j += i;
+  if (j != 55)
+    abort ();
+  if (i != -1)
+    abort ();
+  j = 0;
+  for (register int i = 1; i <= 10; i++)
+    j += i;
+  if (j != 55)
+    abort ();
+  if (i != -1)
+    abort ();
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/c99-fordecl-2.c b/gcc/testsuite/gcc.dg/c99-fordecl-2.c
new file mode 100644 (file)
index 0000000..0ef11f6
--- /dev/null
@@ -0,0 +1,28 @@
+/* Test for C99 declarations in for loops.  Test constraints.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+void
+foo (void)
+{
+  /* See comments in check_for_loop_decls (c-decl.c) for the presumptions
+     behind these tests.  */
+  int j = 0;
+  for (int i = 1, bar (void); i <= 10; i++) /* { dg-bogus "warning" "warning in place of error" } */
+    j += i;
+  /* { dg-error "bar" "function in for loop" { target *-*-* } 12 } */
+  for (static int i = 1; i <= 10; i++) /* { dg-bogus "warning" "warning in place of error" } */
+    j += i;
+  /* { dg-error "static" "static in for loop" { target *-*-* } 15 } */
+  for (extern int i; j <= 500; j++) /* { dg-bogus "warning" "warning in place of error" } */
+    j += 5;
+  /* { dg-error "extern" "extern in for loop" { target *-*-* } 18 } */
+  for (enum { FOO } i = FOO; i < 10; i++) /* { dg-bogus "warning" "warning in place of error" } */
+    j += i;
+  /* { dg-error "FOO" "enum value in for loop" { target *-*-* } 21 } */
+  for (enum BAR { FOO } i = FOO; i < 10; i++) /* { dg-bogus "warning" "warning in place of error" } */
+    j += i;
+  /* { dg-error "FOO" "enum value in for loop" { target *-*-* } 24 } */
+  /* { dg-error "BAR" "enum tag in for loop" { target *-*-* } 24 } */
+}