This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch for C99 "for (int i = 0; i < 10; i++)"


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 } */
+}

-- 
Joseph S. Myers
jsm28@cam.ac.uk


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]