From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6330 invoked by alias); 18 Mar 2010 20:51:12 -0000 Received: (qmail 6311 invoked by uid 22791); 18 Mar 2010 20:51:10 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from e6.ny.us.ibm.com (HELO e6.ny.us.ibm.com) (32.97.182.146) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 18 Mar 2010 20:51:01 +0000 Received: from d01relay06.pok.ibm.com (d01relay06.pok.ibm.com [9.56.227.116]) by e6.ny.us.ibm.com (8.14.3/8.13.1) with ESMTP id o2IKm9gV027263 for ; Thu, 18 Mar 2010 16:48:09 -0400 Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by d01relay06.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o2IKovWn1597482 for ; Thu, 18 Mar 2010 16:50:57 -0400 Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by d01av04.pok.ibm.com (8.14.3/8.13.1/NCO v10.0 AVout) with ESMTP id o2IKov0O007426 for ; Thu, 18 Mar 2010 16:50:57 -0400 Received: from [9.47.18.96] (janis-laptop.beaverton.ibm.com [9.47.18.96]) by d01av04.pok.ibm.com (8.14.3/8.13.1/NCO v10.0 AVin) with ESMTP id o2IKotFp007274 for ; Thu, 18 Mar 2010 16:50:56 -0400 Subject: [PATCH][4.6] detect C++ errors to fix 2288 and 18770 From: Janis Johnson To: gcc-patches@gcc.gnu.org Content-Type: text/plain; charset="UTF-8" Date: Thu, 18 Mar 2010 21:39:00 -0000 Message-ID: <1268945454.2219.13.camel@janis-laptop> Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2010-03/txt/msg00840.txt.bz2 The ISO C++ standard says, in Section 3.3.2 sentence 4, that a name declared in the for-init-statement or in the condition of an if, for while, or switch statement can't be redeclared in the outermost block of the controlled statement (this is not an error in C). This patch detects those errors that were not already detected elsewhere, adds a new test, and removes xfails from an existing test. Tested on powerpc64-linux with bootstrap of all languages but Ada and regtest for -m32/-m64. OK for stage 1 of GCC 4.6? 2010-03-18 Janis Johnson gcc/cp PR c++/2288 PR c++/18770 * name-lookup.h (enum scope_kind): Add sk_cond. * name-lookup.c (pushdecl_maybe_friend): Get scope of shadowed local. Detect and report error for redeclaration from for-init or if or switch condition. (begin_scope): Handle sk_cond. * semantics.c (begin_if_stmt): Use sk_cond. (begin switch_stmt): Ditto. gcc/testsuite/ PR c++/2288 PR c++/18770 * g++.old-deja/g++.jason/cond.C: Remove xfails. * g++.dg/parse/pr18770.C: New test. Index: gcc/cp/name-lookup.h =================================================================== --- gcc/cp/name-lookup.h (revision 157490) +++ gcc/cp/name-lookup.h (working copy) @@ -109,6 +109,8 @@ typedef enum scope_kind { sk_catch, /* A catch-block. */ sk_for, /* The scope of the variable declared in a for-init-statement. */ + sk_cond, /* The scope of the variable declared in the condition + of an if or switch statement. */ sk_function_parms, /* The scope containing function parameters. */ sk_class, /* The scope containing the members of a class. */ sk_scoped_enum, /* The scope containing the enumertors of a C++0x Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 157490) +++ gcc/cp/name-lookup.c (working copy) @@ -946,8 +946,15 @@ pushdecl_maybe_friend (tree x, bool is_f else { /* Here to install a non-global value. */ - tree oldlocal = innermost_non_namespace_value (name); tree oldglobal = IDENTIFIER_NAMESPACE_VALUE (name); + tree oldlocal = NULL_TREE; + cxx_scope *oldscope = NULL; + cxx_binding *oldbinding = outer_binding (name, NULL, true); + if (oldbinding) + { + oldlocal = oldbinding->value; + oldscope = oldbinding->scope; + } if (need_new_binding) { @@ -1051,6 +1058,21 @@ pushdecl_maybe_friend (tree x, bool is_f } } + /* Error if redeclaring a local declared in a for-init-statement + or in the condition of an if or switch statement when the new + declaration is in the outermost block of the controlled + statement. Redeclaring a variable from a for or while + condition is detected elsewhere. */ + else if (oldlocal != NULL_TREE + && TREE_CODE (oldlocal) == VAR_DECL + && oldscope == current_binding_level->level_chain + && (oldscope->kind == sk_cond + || oldscope->kind == sk_for)) + { + error ("redeclaration of %q#D", x); + error ("%q+#D previously declared here", oldlocal); + } + /* Maybe warn if shadowing something else. */ else if (warn_shadow && !DECL_EXTERNAL (x) /* No shadow warnings for internally generated vars. */ @@ -1383,6 +1405,7 @@ begin_scope (scope_kind kind, tree entit case sk_try: case sk_catch: case sk_for: + case sk_cond: case sk_class: case sk_scoped_enum: case sk_function_parms: Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 157490) +++ gcc/cp/semantics.c (working copy) @@ -644,7 +644,7 @@ tree begin_if_stmt (void) { tree r, scope; - scope = do_pushlevel (sk_block); + scope = do_pushlevel (sk_cond); r = build_stmt (input_location, IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE); TREE_CHAIN (r) = scope; begin_cond (&IF_COND (r)); @@ -929,7 +929,7 @@ begin_switch_stmt (void) r = build_stmt (input_location, SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE); - scope = do_pushlevel (sk_block); + scope = do_pushlevel (sk_cond); TREE_CHAIN (r) = scope; begin_cond (&SWITCH_STMT_COND (r)); Index: gcc/testsuite/g++.old-deja/g++.jason/cond.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.jason/cond.C (revision 157490) +++ gcc/testsuite/g++.old-deja/g++.jason/cond.C (working copy) @@ -6,14 +6,14 @@ int main() { float i; - if (int i = 1) // { dg-error "" "" { xfail *-*-* } } , + if (int i = 1) // { dg-error "previously" } { - char i; // { dg-error "" "" { xfail *-*-* } } , + char i; // { dg-error "redeclaration" } char j; } else { - short i; // { dg-error "" "" { xfail *-*-* } } , + short i; // { dg-error "redeclaration" } char j; } @@ -27,10 +27,10 @@ int main() int i; // { dg-error "redeclaration" } } - switch (int i = 0) // { dg-error "" "" { xfail *-*-* } } + switch (int i = 0) // { dg-error "previously" } { default: - int i; // { dg-error "" "" { xfail *-*-* } } + int i; // { dg-error "redeclaration" } } if (struct A { operator int () { return 1; } } *foo = new A) // { dg-error "defined" } Index: gcc/testsuite/g++.dg/parse/pr18770.C =================================================================== --- gcc/testsuite/g++.dg/parse/pr18770.C (revision 0) +++ gcc/testsuite/g++.dg/parse/pr18770.C (revision 0) @@ -0,0 +1,175 @@ +/* { dg-do compile } */ + +/* The ISO C++ standard says, in Section 3.3.2 sentence 4, that a name + declared in the for-init-statement or in the condition of an if, for + while, or switch statement can't be redeclared in the outermost block + of the controlled statement. (Note, this is not an error in C.) */ + +extern void foo (int); +extern int j; + +void +e0 (void) +{ + for (int i = 0; // { dg-error "previously declared here" "prev" } + i < 10; ++i) + { + int i = 2; // { dg-error "redeclaration" "redecl" } + foo (i); + } +} + +void +e1 (void) +{ + int i; + for (i = 0; + int k = j; i++) // { dg-error "previously declared here" "prev" } + { + int k = 2; // { dg-error "redeclaration" "redecl" } + foo (k); + } +} + +void +e2 (void) +{ + if (int i = 1) // { dg-error "previously declared here" "prev" } + { + int i = 2; // { dg-error "redeclaration" "redecl" } + foo (i); + } +} + +void +e3 (void) +{ + if (int i = 1) // { dg-error "previously declared here" "prev" } + { + foo (i); + } + else + { + int i = 2; // { dg-error "redeclaration" "redecl" } + foo (i); + } +} + +void +e4 (void) +{ + while (int i = 1) // { dg-error "previously declared here" "prev" } + { + int i = 2; // { dg-error "redeclaration" "redecl" } + foo (i); + } +} + +void +e5 (void) +{ + switch (int i = j) // { dg-error "previously declared here" "prev" } + { + int i; // { dg-error "redeclaration" "redecl" } + default: + { + i = 2; + foo (i); + } + } +} + +void +f0 (void) +{ + for (int i = 0; i < 10; ++i) + { + foo (i); + { + int i = 2; // OK, not outermost block. + foo (i); + } + } +} + +void +f1 (void) +{ + int i; + for (i = 0; int k = j; i++) + { + foo (k); + { + int k = 2; // OK, not outermost block. + foo (k); + } + } +} + +void +f2 (void) +{ + if (int i = 1) + { + foo (i); + { + int i = 2; // OK, not outermost block. + foo (i); + } + } +} + +void +f3 (void) +{ + if (int i = 1) + { + foo (i); + } + else + { + foo (i+2); + { + int i = 2; // OK, not outermost block. + foo (i); + } + } +} + +void +f4 (void) +{ + while (int i = 1) + { + foo (i); + { + int i = 2; // OK, not outermost block. + foo (i); + } + } +} + +void +f5 (void) +{ + switch (int i = j) + { + default: + { + int i = 2; // OK, not outermost block. + foo (i); + } + } +} + +void +f6 (void) +{ + int i = 1; + + for (int j = 0; j < 10; j++) + { + int i = 2; // OK, not variable from for-init. + foo (i); + } +}