From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31564 invoked by alias); 22 May 2011 19:33:58 -0000 Received: (qmail 31555 invoked by uid 22791); 22 May 2011 19:33:56 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL,BAYES_00,TW_CX,TW_TM,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from bromo.med.uc.edu (HELO bromo.med.uc.edu) (129.137.3.146) by sourceware.org (qpsmtpd/0.43rc1) with SMTP; Sun, 22 May 2011 19:33:37 +0000 Received: from bromo.med.uc.edu (localhost.localdomain [127.0.0.1]) by bromo.med.uc.edu (Postfix) with ESMTP id 79565B0074; Sun, 22 May 2011 15:33:36 -0400 (EDT) Received: (from howarth@localhost) by bromo.med.uc.edu (8.14.3/8.14.3/Submit) id p4MJXZM2009797; Sun, 22 May 2011 15:33:35 -0400 Date: Sun, 22 May 2011 21:24:00 -0000 From: Jack Howarth To: Janis Johnson Cc: gcc-patches@gcc.gnu.org, richard.guenther@gmail.com Subject: Re: [PATCH][4.6] detect C++ errors to fix 2288 and 18770 Message-ID: <20110522193335.GA9729@bromo.med.uc.edu> References: <1268945454.2219.13.camel@janis-laptop> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1268945454.2219.13.camel@janis-laptop> User-Agent: Mutt/1.5.18 (2008-05-17) 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: 2011-05/txt/msg01572.txt.bz2 On Thu, Mar 18, 2010 at 01:50:54PM -0700, Janis Johnson wrote: > 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); > + } > +} > Any chance we can get this committed to gcc trunk while in 4.7 stage 1 (since it was already approved for 4.6 stage 1 and never applied... http://gcc.gnu.org/ml/gcc-patches/2010-05/msg00264.html). It would be nice to have in gcc 4.7 so that other open source projects that only build against g++ would be alerted to fix their sources. Jack