c++: Diagnose [basic.scope.block]/2 violations even in compound-stmt of function-try-block [PR52953]

Message ID ZPA/L5yBEUC3WZxu@tucnak
State Unresolved
Headers
Series c++: Diagnose [basic.scope.block]/2 violations even in compound-stmt of function-try-block [PR52953] |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jakub Jelinek Aug. 31, 2023, 7:20 a.m. UTC
  Hi!

As the following testcase shows, while check_local_shadow diagnoses most of
the [basic.scope.block]/2 violations, it doesn't diagnose when parameter's
name is redeclared inside of the compound-stmt of a function-try-block.

There is in that case an extra scope (sk_try with parent artificial
sk_block with for FUNCTION_NEEDS_BODY_BLOCK another sk_block and only then
sk_function_param).

The following patch fixes that.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2023-08-31  Jakub Jelinek  <jakub@redhat.com>

	PR c++/52953
	* cp-tree.h (struct language_function): Add x_in_function_try_block
	member.
	* semantics.cc (begin_function_try_block): Set it.
	(finish_function_try_block): Clear it.
	* name-lookup.cc (check_local_shadow): If in_function_try_block
	and current_binding_level->kind == sk_try, skip another level.

	* g++.dg/diagnostic/redeclaration-3.C: New test.


	Jakub
  

Comments

Jason Merrill Aug. 31, 2023, 7:52 p.m. UTC | #1
On 8/31/23 03:20, Jakub Jelinek wrote:
> Hi!
> 
> As the following testcase shows, while check_local_shadow diagnoses most of
> the [basic.scope.block]/2 violations, it doesn't diagnose when parameter's
> name is redeclared inside of the compound-stmt of a function-try-block.
> 
> There is in that case an extra scope (sk_try with parent artificial
> sk_block with for FUNCTION_NEEDS_BODY_BLOCK another sk_block and only then
> sk_function_param).
> 
> The following patch fixes that.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2023-08-31  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/52953
> 	* cp-tree.h (struct language_function): Add x_in_function_try_block
> 	member.

How about adding a flag to cp_binding_level instead?  Maybe to mark the 
artificial sk_block level as such, which we could use for both this case 
and the FUNCTION_NEEDS_BODY_BLOCK cases.

Jason
  

Patch

--- gcc/cp/cp-tree.h.jj	2023-08-30 10:42:53.579169729 +0200
+++ gcc/cp/cp-tree.h	2023-08-30 19:28:20.712246064 +0200
@@ -2110,6 +2110,7 @@  struct GTY(()) language_function {
   BOOL_BITFIELD returns_null : 1;
   BOOL_BITFIELD returns_abnormally : 1;
   BOOL_BITFIELD infinite_loop: 1;
+  BOOL_BITFIELD in_function_try_block : 1;
   BOOL_BITFIELD x_in_function_try_handler : 1;
   BOOL_BITFIELD x_in_base_initializer : 1;
 
--- gcc/cp/semantics.cc.jj	2023-08-28 10:33:11.064187885 +0200
+++ gcc/cp/semantics.cc	2023-08-30 19:28:44.295897427 +0200
@@ -1626,6 +1626,7 @@  begin_function_try_block (tree *compound
   *compound_stmt = begin_compound_stmt (0);
   r = begin_try_block ();
   FN_TRY_BLOCK_P (r) = 1;
+  cp_function_chain->in_function_try_block = 1;
   return r;
 }
 
@@ -1662,6 +1663,7 @@  finish_cleanup (tree cleanup, tree try_b
 void
 finish_function_try_block (tree try_block)
 {
+  cp_function_chain->in_function_try_block = 0;
   finish_try_block (try_block);
   /* FIXME : something queer about CTOR_INITIALIZER somehow following
      the try block, but moving it inside.  */
--- gcc/cp/name-lookup.cc.jj	2023-08-24 15:36:59.272791101 +0200
+++ gcc/cp/name-lookup.cc	2023-08-30 19:40:09.396172794 +0200
@@ -3146,6 +3146,11 @@  check_local_shadow (tree decl)
 	     them there.  */
 	  cp_binding_level *b = current_binding_level->level_chain;
 
+	  if (current_binding_level->kind == sk_try
+	      && cp_function_chain->in_function_try_block)
+	    /* Skip the function-try-block level.  */
+	    b = b->level_chain;
+
 	  if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl))
 	    /* Skip the ctor/dtor cleanup level.  */
 	    b = b->level_chain;
--- gcc/testsuite/g++.dg/diagnostic/redeclaration-3.C.jj	2023-08-30 18:51:42.252179367 +0200
+++ gcc/testsuite/g++.dg/diagnostic/redeclaration-3.C	2023-08-30 19:44:06.314933892 +0200
@@ -0,0 +1,204 @@ 
+// PR c++/52953
+// { dg-do compile }
+// { dg-options "-pedantic-errors -Wno-switch-unreachable" }
+
+void
+foo (int x)				// { dg-message "'int x' previously declared here" }
+{
+  int x;				// { dg-error "declaration of 'int x' shadows a parameter" }
+}
+
+void
+bar (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+  int x;				// { dg-error "declaration of 'int x' shadows a parameter" }
+}
+catch (...)
+{
+}
+
+volatile int v;
+
+void
+baz ()
+{
+#if __cplusplus >= 201103L
+  auto f = [] (int x) { int x; };	// { dg-error "declaration of 'int x' shadows a parameter" "" { target c++11 } }
+					// { dg-message "'int x' previously declared here" "" { target c++11 } .-1 }
+#endif
+  if (int x = 1)			// { dg-message "'int x' previously declared here" }
+    {
+      int x;				// { dg-error "redeclaration of 'int x'" }
+    }
+  if (int x = 0)			// { dg-message "'int x' previously declared here" }
+    ;
+  else
+    {
+      int x;				// { dg-error "redeclaration of 'int x'" }
+    }
+  if (int x = 1)			// { dg-message "'int x' previously declared here" }
+    int x;				// { dg-error "redeclaration of 'int x'" }
+  if (int x = 0)			// { dg-message "'int x' previously declared here" }
+    ;
+  else
+    int x;				// { dg-error "redeclaration of 'int x'" }
+  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
+    {
+      int x;				// { dg-error "redeclaration of 'int x'" }
+    default:;
+    }
+  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
+    int x;				// { dg-error "redeclaration of 'int x'" }
+  while (int x = v)			// { dg-message "'int x' previously declared here" }
+    {
+      int x;				// { dg-error "redeclaration of 'int x'" }
+    }
+  while (int x = v)			// { dg-message "'int x' previously declared here" }
+    int x;				// { dg-error "redeclaration of 'int x'" }
+  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
+    {
+      int x;				// { dg-error "redeclaration of 'int x'" }
+    }
+  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
+    int x;				// { dg-error "redeclaration of 'int x'" }
+  for (; int x = v; )			// { dg-message "'int x' previously declared here" }
+    {
+      int x;				// { dg-error "redeclaration of 'int x'" }
+    }
+  for (; int x = v; )			// { dg-message "'int x' previously declared here" }
+    int x;				// { dg-error "redeclaration of 'int x'" }
+  try
+    {
+    }
+  catch (int x)				// { dg-message "'int x' previously declared here" }
+    {
+      int x;				// { dg-error "redeclaration of 'int x'" }
+    }
+  if (int x = 1)
+    if (int x = 1)
+      ;
+  if (int x = 0)
+    ;
+  else
+    if (int x = 1)
+      ;
+  if (int x = 1)
+    switch (int x = 1)
+      ;
+  if (int x = 0)
+    while (int x = v)
+      ;
+  if (int x = 0)
+    for (int x = v; x; ++x)
+      ;
+  switch (int x = 1)
+    switch (int x = 1)
+      {
+      case 1:;
+      }
+  while (int x = 0)
+    if (int x = 1)
+      ;
+  for (int x = v; x; ++x)
+    for (int x = v; x; ++x)
+      ;
+}
+
+void
+qux (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+}
+catch (int x)				// { dg-error "redeclaration of 'int x'" }
+{
+}
+
+void
+corge (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+}
+catch (...)
+{
+  int x;				// { dg-error "redeclaration of 'int x'" }
+}
+
+void
+fred (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+}
+catch (int)
+{
+}
+catch (long)
+{
+  int x;				// { dg-error "redeclaration of 'int x'" }
+}
+
+void
+garply (int x)
+{
+  try
+    {
+      int x;
+    }
+  catch (...)
+    {
+      int x;
+    }
+}
+
+struct S
+{
+  S (int x)				// { dg-message "'int x' previously declared here" }
+  try : s (x)
+  {
+    int x;				// { dg-error "declaration of 'int x' shadows a parameter" }
+  }
+  catch (...)
+  {
+  }
+  int s;
+};
+
+struct T
+{
+  T (int x)				// { dg-message "'int x' previously declared here" }
+  try : t (x)
+  {
+  }
+  catch (...)
+  {
+    int x;				// { dg-error "redeclaration of 'int x'" }
+  }
+  int t;
+};
+
+struct U
+{
+  U (int x) : u (x)
+  {
+    try
+    {
+      int x;
+    }
+    catch (...)
+    {
+      int x;
+    }
+  }
+  int u;
+};
+
+struct V
+{
+  V (int x) : v (x)
+  {
+    {
+      int x;
+    }
+  }
+  int v;
+};