Subject: Patch for C99 "for (int i = 0; i < 10; i++)"
From: "Joseph S. Myers" <jsm28 at cam dot ac dot uk>
Date: Sat, 18 Nov 2000 22:23:36 +0000 (GMT)
This patch adds support for C99 declarations in for loops ("for (int i
= 0; i < 10; i++)"). They are only allowed in C99 mode (-std=c99 /
-std=gnu99) since they only really make sense with the C99 scope
surrounding the for loop.
Bootstrapped with no regressions on i686-pc-linux-gnu. OK to commit?
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 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.
--- c-decl.c.orig Fri Nov 17 18:42:08 2000
+++ c-decl.c Sat Nov 18 17:37:39 2000
@@ -6924,6 +6924,55 @@
}
+/* 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");
+ }
+}
+
/* 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. */
--- c-parse.in.orig Fri Nov 17 07:52:31 2000
+++ c-parse.in Sat Nov 18 20:06:11 2000
@@ -1868,24 +1868,30 @@
| 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); }
c99_block_lineno_labeled_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. */
--- c-tree.h.orig Fri Nov 10 07:51:34 2000
+++ c-tree.h Sat Nov 18 16:09:22 2000
@@ -170,6 +170,7 @@
((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));
--- testsuite/gcc.dg/c90-fordecl-1.c Fri Sep 11 11:31:59 1998
+++ testsuite/gcc.dg/c90-fordecl-1.c Sat Nov 18 16:48:23 2000
@@ -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 } */
+}
--- testsuite/gcc.dg/c99-fordecl-1.c Fri Sep 11 11:31:59 1998
+++ testsuite/gcc.dg/c99-fordecl-1.c Sat Nov 18 16:53:25 2000
@@ -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);
+}
--- testsuite/gcc.dg/c99-fordecl-2.c Fri Sep 11 11:31:59 1998
+++ testsuite/gcc.dg/c99-fordecl-2.c Sat Nov 18 17:32:57 2000
@@ -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 } */
+}