public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][4.6] detect C++ errors to fix 2288 and 18770
@ 2010-03-18 21:39 Janis Johnson
  2010-05-05  2:32 ` Jason Merrill
  2011-05-22 21:24 ` Jack Howarth
  0 siblings, 2 replies; 9+ messages in thread
From: Janis Johnson @ 2010-03-18 21:39 UTC (permalink / raw)
  To: gcc-patches

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  <janis187@us.ibm.com>

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);
+    }
+}


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH][4.6] detect C++ errors to fix 2288 and 18770
  2010-03-18 21:39 [PATCH][4.6] detect C++ errors to fix 2288 and 18770 Janis Johnson
@ 2010-05-05  2:32 ` Jason Merrill
  2011-05-22 21:24 ` Jack Howarth
  1 sibling, 0 replies; 9+ messages in thread
From: Jason Merrill @ 2010-05-05  2:32 UTC (permalink / raw)
  To: Janis Johnson; +Cc: gcc-patches

On 03/18/2010 04:50 PM, Janis Johnson wrote:
> Tested on powerpc64-linux with bootstrap of all languages but Ada and
> regtest for -m32/-m64.  OK for stage 1 of GCC 4.6?

OK.

Jason

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH][4.6] detect C++ errors to fix 2288 and 18770
  2010-03-18 21:39 [PATCH][4.6] detect C++ errors to fix 2288 and 18770 Janis Johnson
  2010-05-05  2:32 ` Jason Merrill
@ 2011-05-22 21:24 ` Jack Howarth
  2011-05-23  7:13   ` Gerald Pfeifer
  1 sibling, 1 reply; 9+ messages in thread
From: Jack Howarth @ 2011-05-22 21:24 UTC (permalink / raw)
  To: Janis Johnson; +Cc: gcc-patches, richard.guenther

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  <janis187@us.ibm.com>
> 
> 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

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH][4.6] detect C++ errors to fix 2288 and 18770
  2011-05-22 21:24 ` Jack Howarth
@ 2011-05-23  7:13   ` Gerald Pfeifer
  2011-05-23  8:34     ` H.J. Lu
  0 siblings, 1 reply; 9+ messages in thread
From: Gerald Pfeifer @ 2011-05-23  7:13 UTC (permalink / raw)
  To: Jack Howarth, Janis Johnson; +Cc: gcc-patches, Richard Guenther

On Sun, 22 May 2011, Jack Howarth wrote:
>> 2010-03-18  Janis Johnson  <janis187@us.ibm.com>
>> 
>> 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.
> 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.

It's my understanding that an approved patch can be committed by anyone 
with write access unless it is retracted or there is some other reason
not to. Customary that is left to the submitter if she has write access,
of course.

In the concrete case, Janis is now reachable at janisjo@codesourcery.com
according to the gcc/MAINTAINERS file, by the way.  Including her...

Gerald

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH][4.6] detect C++ errors to fix 2288 and 18770
  2011-05-23  7:13   ` Gerald Pfeifer
@ 2011-05-23  8:34     ` H.J. Lu
  2011-05-25 19:57       ` Nathan Froyd
  0 siblings, 1 reply; 9+ messages in thread
From: H.J. Lu @ 2011-05-23  8:34 UTC (permalink / raw)
  To: Gerald Pfeifer; +Cc: Jack Howarth, Janis Johnson, gcc-patches, Richard Guenther

On Sun, May 22, 2011 at 2:29 PM, Gerald Pfeifer <gerald@pfeifer.com> wrote:
> On Sun, 22 May 2011, Jack Howarth wrote:
>>> 2010-03-18  Janis Johnson  <janis187@us.ibm.com>
>>>
>>> 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.
>> 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.
>
> It's my understanding that an approved patch can be committed by anyone
> with write access unless it is retracted or there is some other reason
> not to. Customary that is left to the submitter if she has write access,
> of course.
>

FWIW, I tried Janis's patch on 4.6 branch and I got

/export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C: In
function 'void e1()':^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C:29:11:
error: redeclaration of 'int k'^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C:27:12:
error: 'int k' previously declared here^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C: In
function 'void e4()':^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C:63:11:
error: redeclaration of 'int i'^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C:61:14:
error: 'int i' previously declared here^M

FAIL: g++.dg/parse/pr18770.C prev (test for errors, line 14)
FAIL: g++.dg/parse/pr18770.C redecl (test for errors, line 17)
PASS: g++.dg/parse/pr18770.C prev (test for errors, line 27)
PASS: g++.dg/parse/pr18770.C redecl (test for errors, line 29)
FAIL: g++.dg/parse/pr18770.C prev (test for errors, line 37)
FAIL: g++.dg/parse/pr18770.C redecl (test for errors, line 39)
FAIL: g++.dg/parse/pr18770.C prev (test for errors, line 47)
FAIL: g++.dg/parse/pr18770.C redecl (test for errors, line 53)
PASS: g++.dg/parse/pr18770.C prev (test for errors, line 61)
PASS: g++.dg/parse/pr18770.C redecl (test for errors, line 63)
FAIL: g++.dg/parse/pr18770.C prev (test for errors, line 71)
FAIL: g++.dg/parse/pr18770.C redecl (test for errors, line 73)
PASS: g++.dg/parse/pr18770.C (test for excess errors)

/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:
In function 'int main()':^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:22:11:
error: redeclaration of 'int i'^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:20:14:
error: 'int i' previously declared here^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:27:11:
error: redeclaration of 'int i'^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:25:14:
error: 'int i' previously declared here^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:36:16:
error: types may not be defined in conditions^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:39:3:
error: 'A' was not declared in this scope^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:39:5:
error: expected ';' before 'bar'^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:42:12:
error: types may not be defined in conditions^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:42:40:
error: 'one' was not declared in this scope^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:51:14:
warning: declaration of 'int f()' has 'extern' and is initialized
[enabled by default]^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:51:18:
error: function 'int f()' is initialized like a variable^M
/export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:55:23:
error: extended initializer lists only available with -std=c++0x or
-std=gnu++0x^M

FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 9)
FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 11)
FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 16)
PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 20)
PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 22)
PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 25)
PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 27)
FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 30)
FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 33)
PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 36)
PASS: g++.old-deja/g++.jason/cond.C decl (test for errors, line 39)
PASS: g++.old-deja/g++.jason/cond.C exp (test for errors, line 39)
PASS: g++.old-deja/g++.jason/cond.C def (test for errors, line 42)
PASS: g++.old-deja/g++.jason/cond.C expected (test for errors, line 42)
PASS: g++.old-deja/g++.jason/cond.C extern (test for warnings, line 51)

The patch no longer catches all problems.


-- 
H.J.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH][4.6] detect C++ errors to fix 2288 and 18770
  2011-05-23  8:34     ` H.J. Lu
@ 2011-05-25 19:57       ` Nathan Froyd
  2011-05-26  8:11         ` Nathan Froyd
  0 siblings, 1 reply; 9+ messages in thread
From: Nathan Froyd @ 2011-05-25 19:57 UTC (permalink / raw)
  To: H.J. Lu
  Cc: Gerald Pfeifer, Jack Howarth, Janis Johnson, gcc-patches,
	Richard Guenther, jason

On Sun, May 22, 2011 at 03:25:41PM -0700, H.J. Lu wrote:
> FWIW, I tried Janis's patch on 4.6 branch and I got
> 
> /export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C: In
> function 'void e1()':^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C:29:11:
> error: redeclaration of 'int k'^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C:27:12:
> error: 'int k' previously declared here^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C: In
> function 'void e4()':^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C:63:11:
> error: redeclaration of 'int i'^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.dg/parse/pr18770.C:61:14:
> error: 'int i' previously declared here^M
> 
> FAIL: g++.dg/parse/pr18770.C prev (test for errors, line 14)
> FAIL: g++.dg/parse/pr18770.C redecl (test for errors, line 17)
> PASS: g++.dg/parse/pr18770.C prev (test for errors, line 27)
> PASS: g++.dg/parse/pr18770.C redecl (test for errors, line 29)
> FAIL: g++.dg/parse/pr18770.C prev (test for errors, line 37)
> FAIL: g++.dg/parse/pr18770.C redecl (test for errors, line 39)
> FAIL: g++.dg/parse/pr18770.C prev (test for errors, line 47)
> FAIL: g++.dg/parse/pr18770.C redecl (test for errors, line 53)
> PASS: g++.dg/parse/pr18770.C prev (test for errors, line 61)
> PASS: g++.dg/parse/pr18770.C redecl (test for errors, line 63)
> FAIL: g++.dg/parse/pr18770.C prev (test for errors, line 71)
> FAIL: g++.dg/parse/pr18770.C redecl (test for errors, line 73)
> PASS: g++.dg/parse/pr18770.C (test for excess errors)
> 
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:
> In function 'int main()':^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:22:11:
> error: redeclaration of 'int i'^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:20:14:
> error: 'int i' previously declared here^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:27:11:
> error: redeclaration of 'int i'^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:25:14:
> error: 'int i' previously declared here^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:36:16:
> error: types may not be defined in conditions^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:39:3:
> error: 'A' was not declared in this scope^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:39:5:
> error: expected ';' before 'bar'^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:42:12:
> error: types may not be defined in conditions^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:42:40:
> error: 'one' was not declared in this scope^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:51:14:
> warning: declaration of 'int f()' has 'extern' and is initialized
> [enabled by default]^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:51:18:
> error: function 'int f()' is initialized like a variable^M
> /export/gnu/import/git/gcc/gcc/testsuite/g++.old-deja/g++.jason/cond.C:55:23:
> error: extended initializer lists only available with -std=c++0x or
> -std=gnu++0x^M
> 
> FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 9)
> FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 11)
> FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 16)
> PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 20)
> PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 22)
> PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 25)
> PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 27)
> FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 30)
> FAIL: g++.old-deja/g++.jason/cond.C  (test for errors, line 33)
> PASS: g++.old-deja/g++.jason/cond.C  (test for errors, line 36)
> PASS: g++.old-deja/g++.jason/cond.C decl (test for errors, line 39)
> PASS: g++.old-deja/g++.jason/cond.C exp (test for errors, line 39)
> PASS: g++.old-deja/g++.jason/cond.C def (test for errors, line 42)
> PASS: g++.old-deja/g++.jason/cond.C expected (test for errors, line 42)
> PASS: g++.old-deja/g++.jason/cond.C extern (test for warnings, line 51)
> 
> The patch no longer catches all problems.

The patch just requires some shuffling of logic to catch issues now;
below is a version that works for me on the trunk.

This new checking does require modifying g++.dg/cpp0x/range-for5.C.  The
new logic of the patch claims that:

  int i;
  for (int i : a)
  {
    int i;
  }

is incorrect (the innermost `i' is an erroneous redeclaration).  If you
apply the expansion of range-based for loops from [stmt.ranged]p1, you'd
get something like:

  for (...; ...; ...)
   {
     int i = ...;
     int i;
   }

which is bad.  I believe [basic.scope.local]p4 says much the same thing.

Tested with g++ testsuite on x86_64-unknown-linux-gnu; tests in progress
for libstdc++.  OK to commit?

-Nathan

gcc/cp/
2011-xx-xx  Janis Johnson  <janisjo@codesourcery.com>
	    Nathan Froyd  <froydnj@codesourcery.com>

	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/
2011-xx-xx  Janis Johnson  <janisjo@codesourcery.com>
	    Nathan Froyd  <froydnj@codesourcery.com>

	PR c++/2288
	PR c++/18770
	* g++.old-deja/g++.jason/cond.C: Remove xfails.
	* g++.dg/parse/pr18770.C: New test.
	* g++.dg/cpp0x/range-for5.C: Add dg-error marker.

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index bb6d4b9..723f36f 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -957,8 +957,15 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
       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)
 	    {
@@ -1087,6 +1094,20 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 		       }
 		   }
 		}
+	      /* 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 (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);
+		}
 
 	      if (warn_shadow && !nowarn)
 		{
@@ -1446,6 +1467,7 @@ begin_scope (scope_kind kind, tree entity)
     case sk_try:
     case sk_catch:
     case sk_for:
+    case sk_cond:
     case sk_class:
     case sk_scoped_enum:
     case sk_function_parms:
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 4bf253f..90b56e4 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -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
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 55ad117..7833d76 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -656,7 +656,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, scope);
   begin_cond (&IF_COND (r));
@@ -1013,7 +1013,7 @@ begin_switch_stmt (void)
 {
   tree r, scope;
 
-  scope = do_pushlevel (sk_block);
+  scope = do_pushlevel (sk_cond);
   r = build_stmt (input_location, SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE, scope);
 
   begin_cond (&SWITCH_STMT_COND (r));
diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for5.C b/gcc/testsuite/g++.dg/cpp0x/range-for5.C
index 9c97ad5..2fe4702 100644
--- a/gcc/testsuite/g++.dg/cpp0x/range-for5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/range-for5.C
@@ -49,6 +49,6 @@ void test1()
   int i;
   for (int i : a)
   {
-    int i;
+    int i;			// { dg-error "redeclaration" }
   }
 }
diff --git a/gcc/testsuite/g++.dg/parse/pr18770.C b/gcc/testsuite/g++.dg/parse/pr18770.C
new file mode 100644
index 0000000..df57be4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/pr18770.C
@@ -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);
+    }
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/cond.C b/gcc/testsuite/g++.old-deja/g++.jason/cond.C
index d0616e4..a6e5ba0 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/cond.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/cond.C
@@ -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" } 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH][4.6] detect C++ errors to fix 2288 and 18770
  2011-05-25 19:57       ` Nathan Froyd
@ 2011-05-26  8:11         ` Nathan Froyd
  2011-05-26 18:24           ` Peter Bergner
  2011-05-26 19:17           ` Jason Merrill
  0 siblings, 2 replies; 9+ messages in thread
From: Nathan Froyd @ 2011-05-26  8:11 UTC (permalink / raw)
  To: H.J. Lu
  Cc: Gerald Pfeifer, Jack Howarth, Janis Johnson, gcc-patches,
	Richard Guenther, jason

On Wed, May 25, 2011 at 03:22:07PM -0400, Nathan Froyd wrote:
> The patch just requires some shuffling of logic to catch issues now;
> below is a version that works for me on the trunk.
> 
> This new checking does require modifying g++.dg/cpp0x/range-for5.C.
> 
> Tested with g++ testsuite on x86_64-unknown-linux-gnu; tests in progress
> for libstdc++.  OK to commit?

Below is a slightly revised patch that actually adds all the necessary
dg-error directives to range-for5.C.  Tested the same way; Peter Bergner
was kind enough to bootstrap and test the previous patch on
powerpc64-linux-gnu with (almost) clean results as well.

gcc/cp/
2011-xx-xx  Janis Johnson  <janisjo@codesourcery.com>
	    Nathan Froyd  <froydnj@codesourcery.com>

	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/
2011-xx-xx  Janis Johnson  <janisjo@codesourcery.com>
	    Nathan Froyd  <froydnj@codesourcery.com>

	PR c++/2288
	PR c++/18770
	* g++.old-deja/g++.jason/cond.C: Remove xfails.
	* g++.dg/parse/pr18770.C: New test.
	* g++.dg/cpp0x/range-for5.C: Add dg-error marker.

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index bb6d4b9..723f36f 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -957,8 +957,15 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
       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)
 	    {
@@ -1087,6 +1094,20 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 		       }
 		   }
 		}
+	      /* 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 (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);
+		}
 
 	      if (warn_shadow && !nowarn)
 		{
@@ -1446,6 +1467,7 @@ begin_scope (scope_kind kind, tree entity)
     case sk_try:
     case sk_catch:
     case sk_for:
+    case sk_cond:
     case sk_class:
     case sk_scoped_enum:
     case sk_function_parms:
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 4bf253f..90b56e4 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -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
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 55ad117..7833d76 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -656,7 +656,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, scope);
   begin_cond (&IF_COND (r));
@@ -1013,7 +1013,7 @@ begin_switch_stmt (void)
 {
   tree r, scope;
 
-  scope = do_pushlevel (sk_block);
+  scope = do_pushlevel (sk_cond);
   r = build_stmt (input_location, SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE, scope);
 
   begin_cond (&SWITCH_STMT_COND (r));
diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for5.C b/gcc/testsuite/g++.dg/cpp0x/range-for5.C
index 9c97ad5..fd6f761 100644
--- a/gcc/testsuite/g++.dg/cpp0x/range-for5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/range-for5.C
@@ -47,8 +47,8 @@ void test1()
 
   //Check the correct scopes
   int i;
-  for (int i : a)
+  for (int i : a)		// { dg-error "previously declared" }
   {
-    int i;
+    int i;			// { dg-error "redeclaration" }
   }
 }
diff --git a/gcc/testsuite/g++.dg/parse/pr18770.C b/gcc/testsuite/g++.dg/parse/pr18770.C
new file mode 100644
index 0000000..df57be4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/pr18770.C
@@ -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);
+    }
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/cond.C b/gcc/testsuite/g++.old-deja/g++.jason/cond.C
index d0616e4..a6e5ba0 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/cond.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/cond.C
@@ -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" } 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH][4.6] detect C++ errors to fix 2288 and 18770
  2011-05-26  8:11         ` Nathan Froyd
@ 2011-05-26 18:24           ` Peter Bergner
  2011-05-26 19:17           ` Jason Merrill
  1 sibling, 0 replies; 9+ messages in thread
From: Peter Bergner @ 2011-05-26 18:24 UTC (permalink / raw)
  To: Nathan Froyd
  Cc: H.J. Lu, Gerald Pfeifer, Jack Howarth, Janis Johnson,
	gcc-patches, Richard Guenther, jason

On Wed, 2011-05-25 at 21:24 -0400, Nathan Froyd wrote:
> On Wed, May 25, 2011 at 03:22:07PM -0400, Nathan Froyd wrote:
> > The patch just requires some shuffling of logic to catch issues now;
> > below is a version that works for me on the trunk.
> > 
> > This new checking does require modifying g++.dg/cpp0x/range-for5.C.
> > 
> > Tested with g++ testsuite on x86_64-unknown-linux-gnu; tests in progress
> > for libstdc++.  OK to commit?
> 
> Below is a slightly revised patch that actually adds all the necessary
> dg-error directives to range-for5.C.  Tested the same way; Peter Bergner
> was kind enough to bootstrap and test the previous patch on
> powerpc64-linux-gnu with (almost) clean results as well.

FYI, the revised patch passes bootstrap and regtesting (-m32 and -m64) with
no regressions on powerpc64-linux.

Peter



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH][4.6] detect C++ errors to fix 2288 and 18770
  2011-05-26  8:11         ` Nathan Froyd
  2011-05-26 18:24           ` Peter Bergner
@ 2011-05-26 19:17           ` Jason Merrill
  1 sibling, 0 replies; 9+ messages in thread
From: Jason Merrill @ 2011-05-26 19:17 UTC (permalink / raw)
  To: Nathan Froyd
  Cc: H.J. Lu, Gerald Pfeifer, Jack Howarth, Janis Johnson,
	gcc-patches, Richard Guenther

OK for 4.7.

Jason

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2011-05-26 18:23 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-18 21:39 [PATCH][4.6] detect C++ errors to fix 2288 and 18770 Janis Johnson
2010-05-05  2:32 ` Jason Merrill
2011-05-22 21:24 ` Jack Howarth
2011-05-23  7:13   ` Gerald Pfeifer
2011-05-23  8:34     ` H.J. Lu
2011-05-25 19:57       ` Nathan Froyd
2011-05-26  8:11         ` Nathan Froyd
2011-05-26 18:24           ` Peter Bergner
2011-05-26 19:17           ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).