From: Joseph Myers Date: Sat, 18 Nov 2000 23:18:36 +0000 (+0000) Subject: c-decl.c (check_for_loop_decls): New function. X-Git-Tag: prereleases/libstdc++-2.92~2917 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=77c4d6c06a83f7d86471befb76a1be433dc2e3a3;p=thirdparty%2Fgcc.git c-decl.c (check_for_loop_decls): New function. * 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. testsuite: * gcc.dg/c90-fordecl-1.c, gcc.dg/c99-fordecl-1.c, gcc.dg/c99-fordecl-2.c: New tests. From-SVN: r37549 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9e5850ef5c18..e80a4892ed46 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2000-11-18 Joseph S. Myers + + * 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 * cppinit.c: Update comments. diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 8d66b4ef2605..d97419d2e99f 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -6924,6 +6924,55 @@ c_expand_body (fndecl, nested_p) } +/* 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. */ diff --git a/gcc/c-parse.in b/gcc/c-parse.in index ae474667ff63..517b488c9d9a 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -1868,19 +1868,18 @@ select_or_iter_stmt: | do_stmt_start error { } | FOR - '(' xexpr ';' - { stmt_count++; - $3 = build_stmt (EXPR_STMT, $3); - $$ = build_stmt (FOR_STMT, $3, NULL_TREE, + { $$ = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); - add_stmt ($$); - } + add_stmt ($$); } + '(' for_init_stmt + { stmt_count++; + RECHAIN_STMTS ($2, FOR_INIT_STMT ($2)); } xexpr ';' - { FOR_COND ($5) = $6; } + { FOR_COND ($2) = $6; } xexpr ')' - { FOR_EXPR ($5) = $9; } + { FOR_EXPR ($2) = $9; } c99_block_lineno_labeled_stmt - { RECHAIN_STMTS ($5, FOR_BODY ($5)); } + { RECHAIN_STMTS ($2, FOR_BODY ($2)); } | SWITCH '(' expr ')' { stmt_count++; $$ = 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 diff --git a/gcc/c-tree.h b/gcc/c-tree.h index efd5083e7ebb..669c89b7d1bd 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -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)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6b0dcaaf0c18..78eb81f8c6af 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2000-11-18 Joseph S. Myers + + * 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 * 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 index 000000000000..8e48dd61752d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-fordecl-1.c @@ -0,0 +1,13 @@ +/* Test for C99 declarations in for loops - rejection in C90 mode. */ +/* Origin: Joseph Myers */ +/* { 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 index 000000000000..faaab1e9539f --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-fordecl-1.c @@ -0,0 +1,35 @@ +/* Test for C99 declarations in for loops. */ +/* Origin: Joseph Myers */ +/* { 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 index 000000000000..0ef11f612252 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-fordecl-2.c @@ -0,0 +1,28 @@ +/* Test for C99 declarations in for loops. Test constraints. */ +/* Origin: Joseph Myers */ +/* { 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 } */ +}