c++, v2: Diagnose [basic.scope.block]/2 violations even for block externs [PR52953]

Message ID ZPHoWgZhqZFQP8cX@tucnak
State Unresolved
Headers
Series c++, v2: Diagnose [basic.scope.block]/2 violations even for block externs [PR52953] |

Checks

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

Commit Message

Jakub Jelinek Sept. 1, 2023, 1:34 p.m. UTC
  On Thu, Aug 31, 2023 at 05:46:28PM -0400, Jason Merrill wrote:
> I've suggested this to Core.

Thanks.

> > So, I'm not really sure what to do.  Intuitively the patch seems right
> > because even block externs redeclare stuff and change meaning of the
> > identifiers and void foo () { int i; extern int i (int); } is rejected
> > by all compilers.
> 
> I think this direction makes sense, though we might pedwarn on these rather
> than error to reduce possible breakage.

It wasn't clear to me whether you want to make those pedwarns just for the
DECL_EXTERNAL cases, ones that actually changed, or all others as well
(which were errors or permerrors depending on the case).
I've implemented the former, kept existing behavior of !DECL_EXTERNAL.

> > 2023-08-31  Jakub Jelinek  <jakub@redhat.com>
> > 
> > 	PR c++/52953
> > 	* name-lookup.cc (check_local_shadow): Defer punting on
> > 	DECL_EXTERNAL (decl) from the start of function to right before
> > 	the -Wshadow* checks.
> 
> Don't we want to consider externs for the -Wshadow* checks as well?

I think that is a good idea (though dunno how much it will trigger in
real-world), but there is one case I've excluded, the global variable
shadowing case, because warning that
int z;
void foo () { extern int z; z = 1; }
shadows the global var would be incorrect, it is the same var.
It is true that
int y; namespace N { void bar () { extern int y; y = 1; } }
shadows ::y but it is unclear how to differentiate those two cases with
the information we have at check_local_shadow time.

I've also found one spot which wasn't using auto_diagnostic_group d;
on a pair of error_at/inform.

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

2023-09-01  Jakub Jelinek  <jakub@redhat.com>

	PR c++/52953
	* name-lookup.cc (check_local_shadow): Don't punt early for
	DECL_EXTERNAL decls, instead just disable the shadowing of namespace
	decls check for those and emit a pedwarn rather than error_at for
	those.  Add missing auto_diagnostic_group.  Formatting fix.

	* g++.dg/diagnostic/redeclaration-4.C: New test.
	* g++.dg/diagnostic/redeclaration-5.C: New test.
	* g++.dg/warn/Wshadow-19.C: New test.



	Jakub
  

Comments

Jason Merrill Sept. 5, 2023, 2 p.m. UTC | #1
On 9/1/23 09:34, Jakub Jelinek wrote:
> On Thu, Aug 31, 2023 at 05:46:28PM -0400, Jason Merrill wrote:
>> I've suggested this to Core.
> 
> Thanks.
> 
>>> So, I'm not really sure what to do.  Intuitively the patch seems right
>>> because even block externs redeclare stuff and change meaning of the
>>> identifiers and void foo () { int i; extern int i (int); } is rejected
>>> by all compilers.
>>
>> I think this direction makes sense, though we might pedwarn on these rather
>> than error to reduce possible breakage.
> 
> It wasn't clear to me whether you want to make those pedwarns just for the
> DECL_EXTERNAL cases, ones that actually changed, or all others as well
> (which were errors or permerrors depending on the case).
> I've implemented the former, kept existing behavior of !DECL_EXTERNAL.
> 
>>> 2023-08-31  Jakub Jelinek  <jakub@redhat.com>
>>>
>>> 	PR c++/52953
>>> 	* name-lookup.cc (check_local_shadow): Defer punting on
>>> 	DECL_EXTERNAL (decl) from the start of function to right before
>>> 	the -Wshadow* checks.
>>
>> Don't we want to consider externs for the -Wshadow* checks as well?
> 
> I think that is a good idea (though dunno how much it will trigger in
> real-world), but there is one case I've excluded, the global variable
> shadowing case, because warning that
> int z;
> void foo () { extern int z; z = 1; }
> shadows the global var would be incorrect, it is the same var.
> It is true that
> int y; namespace N { void bar () { extern int y; y = 1; } }
> shadows ::y but it is unclear how to differentiate those two cases with
> the information we have at check_local_shadow time.
> 
> I've also found one spot which wasn't using auto_diagnostic_group d;
> on a pair of error_at/inform.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

> 2023-09-01  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/52953
> 	* name-lookup.cc (check_local_shadow): Don't punt early for
> 	DECL_EXTERNAL decls, instead just disable the shadowing of namespace
> 	decls check for those and emit a pedwarn rather than error_at for
> 	those.  Add missing auto_diagnostic_group.  Formatting fix.
> 
> 	* g++.dg/diagnostic/redeclaration-4.C: New test.
> 	* g++.dg/diagnostic/redeclaration-5.C: New test.
> 	* g++.dg/warn/Wshadow-19.C: New test.
> 
> --- gcc/cp/name-lookup.cc.jj	2023-09-01 10:21:03.658118594 +0200
> +++ gcc/cp/name-lookup.cc	2023-09-01 11:30:10.868516494 +0200
> @@ -3096,10 +3096,6 @@ check_local_shadow (tree decl)
>     if (TREE_CODE (decl) == PARM_DECL && !DECL_CONTEXT (decl))
>       return;
>   
> -  /* External decls are something else.  */
> -  if (DECL_EXTERNAL (decl))
> -    return;
> -
>     tree old = NULL_TREE;
>     cp_binding_level *old_scope = NULL;
>     if (cxx_binding *binding = outer_binding (DECL_NAME (decl), NULL, true))
> @@ -3130,11 +3126,9 @@ check_local_shadow (tree decl)
>   	      && DECL_CONTEXT (old) == lambda_function (current_lambda_expr ())
>   	      && TREE_CODE (old) == PARM_DECL
>   	      && DECL_NAME (decl) != this_identifier)
> -	    {
> -	      error_at (DECL_SOURCE_LOCATION (old),
> -			"lambda parameter %qD "
> -			"previously declared as a capture", old);
> -	    }
> +	    error_at (DECL_SOURCE_LOCATION (old),
> +		      "lambda parameter %qD "
> +		      "previously declared as a capture", old);
>   	  return;
>   	}
>         /* Don't complain if it's from an enclosing function.  */
> @@ -3156,10 +3150,18 @@ check_local_shadow (tree decl)
>   	     in the outermost block of the function definition.  */
>   	  if (b->kind == sk_function_parms)
>   	    {
> -	      error_at (DECL_SOURCE_LOCATION (decl),
> -			"declaration of %q#D shadows a parameter", decl);
> -	      inform (DECL_SOURCE_LOCATION (old),
> -		      "%q#D previously declared here", old);
> +	      auto_diagnostic_group d;
> +	      bool emit = true;
> +	      if (DECL_EXTERNAL (decl))
> +		emit = pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic,
> +				"declaration of %q#D shadows a parameter",
> +				decl);
> +	      else
> +		error_at (DECL_SOURCE_LOCATION (decl),
> +			  "declaration of %q#D shadows a parameter", decl);
> +	      if (emit)
> +		inform (DECL_SOURCE_LOCATION (old),
> +			"%q#D previously declared here", old);
>   	      return;
>   	    }
>   	}
> @@ -3185,10 +3187,16 @@ check_local_shadow (tree decl)
>   	       && (old_scope->kind == sk_cond || old_scope->kind == sk_for))
>   	{
>   	  auto_diagnostic_group d;
> -	  error_at (DECL_SOURCE_LOCATION (decl),
> -		    "redeclaration of %q#D", decl);
> -	  inform (DECL_SOURCE_LOCATION (old),
> -		  "%q#D previously declared here", old);
> +	  bool emit = true;
> +	  if (DECL_EXTERNAL (decl))
> +	    emit = pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic,
> +			    "redeclaration of %q#D", decl);
> +	  else
> +	    error_at (DECL_SOURCE_LOCATION (decl),
> +		      "redeclaration of %q#D", decl);
> +	  if (emit)
> +	    inform (DECL_SOURCE_LOCATION (old),
> +		    "%q#D previously declared here", old);
>   	  return;
>   	}
>         /* C++11:
> @@ -3314,6 +3322,7 @@ check_local_shadow (tree decl)
>   	  || (TREE_CODE (old) == TYPE_DECL
>   	      && (!DECL_ARTIFICIAL (old)
>   		  || TREE_CODE (decl) == TYPE_DECL)))
> +      && !DECL_EXTERNAL (decl)
>         && !instantiating_current_function_p ()
>         && !warning_suppressed_p (decl, OPT_Wshadow))
>       /* XXX shadow warnings in outer-more namespaces */
> --- gcc/testsuite/g++.dg/diagnostic/redeclaration-4.C.jj	2023-09-01 10:46:15.646025458 +0200
> +++ gcc/testsuite/g++.dg/diagnostic/redeclaration-4.C	2023-09-01 10:46:15.646025458 +0200
> @@ -0,0 +1,167 @@
> +// PR c++/52953
> +// { dg-do compile }
> +// { dg-options "-pedantic-errors -Wno-switch-unreachable" }
> +
> +void
> +foo (int x)				// { dg-message "'int x' previously declared here" }
> +{
> +  extern int x;				// { dg-error "declaration of 'int x' shadows a parameter" }
> +}
> +
> +void
> +bar (int x)				// { dg-message "'int x' previously declared here" }
> +try
> +{
> +  extern int x;				// { dg-error "declaration of 'int x' shadows a parameter" }
> +}
> +catch (...)
> +{
> +}
> +
> +volatile int v;
> +
> +void
> +baz ()
> +{
> +#if __cplusplus >= 201103L
> +  auto f = [] (int x) { extern 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" }
> +    {
> +      extern int x;			// { dg-error "redeclaration of 'int x'" }
> +    }
> +  if (int x = 0)			// { dg-message "'int x' previously declared here" }
> +    ;
> +  else
> +    {
> +      extern int x;			// { dg-error "redeclaration of 'int x'" }
> +    }
> +  if (int x = 1)			// { dg-message "'int x' previously declared here" }
> +    extern int x;			// { dg-error "redeclaration of 'int x'" }
> +  if (int x = 0)			// { dg-message "'int x' previously declared here" }
> +    ;
> +  else
> +    extern int x;			// { dg-error "redeclaration of 'int x'" }
> +  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
> +    {
> +      extern int x;			// { dg-error "redeclaration of 'int x'" }
> +    default:;
> +    }
> +  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
> +    extern int x;			// { dg-error "redeclaration of 'int x'" }
> +  while (int x = v)
> +    {
> +      extern int x;			// { dg-error "'int x' conflicts with a previous declaration" }
> +    }
> +  while (int x = v)
> +    extern int x;			// { dg-error "'int x' conflicts with a previous declaration" }
> +  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
> +    {
> +      extern int x;			// { dg-error "redeclaration of 'int x'" }
> +    }
> +  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
> +    extern int x;			// { dg-error "redeclaration of 'int x'" }
> +  for (; int x = v; )
> +    {
> +      extern int x;			// { dg-error "'int x' conflicts with a previous declaration" }
> +    }
> +  for (; int x = v; )
> +    extern int x;			// { dg-error "'int x' conflicts with a previous declaration" }
> +  try
> +    {
> +    }
> +  catch (int x)				// { dg-message "'int x' previously declared here" }
> +    {
> +      extern int x;			// { dg-error "redeclaration of 'int x'" }
> +    }
> +}
> +
> +void
> +corge (int x)				// { dg-message "'int x' previously declared here" }
> +try
> +{
> +}
> +catch (...)
> +{
> +  extern int x;				// { dg-error "redeclaration of 'int x'" }
> +}
> +
> +void
> +fred (int x)				// { dg-message "'int x' previously declared here" }
> +try
> +{
> +}
> +catch (int)
> +{
> +}
> +catch (long)
> +{
> +  extern int x;				// { dg-error "redeclaration of 'int x'" }
> +}
> +
> +void
> +garply (int x)
> +{
> +  try
> +    {
> +      extern int x;
> +    }
> +  catch (...)
> +    {
> +      extern int x;
> +    }
> +}
> +
> +struct S
> +{
> +  S (int x)				// { dg-message "'int x' previously declared here" }
> +  try : s (x)
> +  {
> +    extern 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 (...)
> +  {
> +    extern int x;				// { dg-error "redeclaration of 'int x'" }
> +  }
> +  int t;
> +};
> +
> +struct U
> +{
> +  U (int x) : u (x)
> +  {
> +    try
> +    {
> +      extern int x;
> +    }
> +    catch (...)
> +    {
> +      extern int x;
> +    }
> +  }
> +  int u;
> +};
> +
> +struct V
> +{
> +  V (int x) : v (x)
> +  {
> +    {
> +      extern int x;
> +    }
> +  }
> +  int v;
> +};
> --- gcc/testsuite/g++.dg/diagnostic/redeclaration-5.C.jj	2023-09-01 10:46:15.646025458 +0200
> +++ gcc/testsuite/g++.dg/diagnostic/redeclaration-5.C	2023-09-01 10:46:15.646025458 +0200
> @@ -0,0 +1,167 @@
> +// PR c++/52953
> +// { dg-do compile }
> +// { dg-options "-pedantic-errors -Wno-switch-unreachable" }
> +
> +void
> +foo (int x)				// { dg-message "'int x' previously declared here" }
> +{
> +  extern int x (int);			// { dg-error "declaration of 'int x\\\(int\\\)' shadows a parameter" }
> +}
> +
> +void
> +bar (int x)				// { dg-message "'int x' previously declared here" }
> +try
> +{
> +  extern int x (int);			// { dg-error "declaration of 'int x\\\(int\\\)' shadows a parameter" }
> +}
> +catch (...)
> +{
> +}
> +
> +volatile int v;
> +
> +void
> +baz ()
> +{
> +#if __cplusplus >= 201103L
> +  auto f = [] (int x) { extern int x (int); };// { dg-error "declaration of 'int x\\\(int\\\)' 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" }
> +    {
> +      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +    }
> +  if (int x = 0)			// { dg-message "'int x' previously declared here" }
> +    ;
> +  else
> +    {
> +      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +    }
> +  if (int x = 1)			// { dg-message "'int x' previously declared here" }
> +    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +  if (int x = 0)			// { dg-message "'int x' previously declared here" }
> +    ;
> +  else
> +    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
> +    {
> +      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +    default:;
> +    }
> +  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
> +    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +  while (int x = v)
> +    {
> +      extern int x (int);		// { dg-error "'int x\\\(int\\\)' redeclared as different kind of entity" }
> +    }
> +  while (int x = v)
> +    extern int x (int);			// { dg-error "'int x\\\(int\\\)' redeclared as different kind of entity" }
> +  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
> +    {
> +      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +    }
> +  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
> +    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +  for (; int x = v; )
> +    {
> +      extern int x (int);		// { dg-error "'int x\\\(int\\\)' redeclared as different kind of entity" }
> +    }
> +  for (; int x = v; )
> +    extern int x (int);			// { dg-error "'int x\\\(int\\\)' redeclared as different kind of entity" }
> +  try
> +    {
> +    }
> +  catch (int x)				// { dg-message "'int x' previously declared here" }
> +    {
> +      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +    }
> +}
> +
> +void
> +corge (int x)				// { dg-message "'int x' previously declared here" }
> +try
> +{
> +}
> +catch (...)
> +{
> +  extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +}
> +
> +void
> +fred (int x)				// { dg-message "'int x' previously declared here" }
> +try
> +{
> +}
> +catch (int)
> +{
> +}
> +catch (long)
> +{
> +  extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +}
> +
> +void
> +garply (int x)
> +{
> +  try
> +    {
> +      extern int x (int);
> +    }
> +  catch (...)
> +    {
> +      extern int x (int);
> +    }
> +}
> +
> +struct S
> +{
> +  S (int x)				// { dg-message "'int x' previously declared here" }
> +  try : s (x)
> +  {
> +    extern int x (int);			// { dg-error "declaration of 'int x\\\(int\\\)' shadows a parameter" }
> +  }
> +  catch (...)
> +  {
> +  }
> +  int s;
> +};
> +
> +struct T
> +{
> +  T (int x)				// { dg-message "'int x' previously declared here" }
> +  try : t (x)
> +  {
> +  }
> +  catch (...)
> +  {
> +    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
> +  }
> +  int t;
> +};
> +
> +struct U
> +{
> +  U (int x) : u (x)
> +  {
> +    try
> +    {
> +      extern int x (int);
> +    }
> +    catch (...)
> +    {
> +      extern int x (int);
> +    }
> +  }
> +  int u;
> +};
> +
> +struct V
> +{
> +  V (int x) : v (x)
> +  {
> +    {
> +      extern int x (int);
> +    }
> +  }
> +  int v;
> +};
> --- gcc/testsuite/g++.dg/warn/Wshadow-19.C.jj	2023-09-01 11:35:21.092200057 +0200
> +++ gcc/testsuite/g++.dg/warn/Wshadow-19.C	2023-09-01 11:37:15.997598483 +0200
> @@ -0,0 +1,27 @@
> +// { dg-do compile }
> +// { dg-options "-Wshadow" }
> +
> +void
> +foo (int x)
> +{
> +  int y = 1;
> +  {
> +    extern int x;				// { dg-warning "declaration of 'int x' shadows a parameter" }
> +    extern int y;				// { dg-warning "declaration of 'y' shadows a previous local" }
> +  }
> +#if __cplusplus >= 201102L
> +  auto fn = [x] () { extern int x; return 0; };	// { dg-warning "declaration of 'x' shadows a lambda capture" "" { target c++11 } }
> +#endif
> +}
> +
> +int z;
> +
> +struct S
> +{
> +  int x;
> +  void foo ()
> +  {
> +    extern int x;				// { dg-warning "declaration of 'x' shadows a member of 'S'" }
> +    extern int z;
> +  }
> +};
> 
> 
> 	Jakub
>
  

Patch

--- gcc/cp/name-lookup.cc.jj	2023-09-01 10:21:03.658118594 +0200
+++ gcc/cp/name-lookup.cc	2023-09-01 11:30:10.868516494 +0200
@@ -3096,10 +3096,6 @@  check_local_shadow (tree decl)
   if (TREE_CODE (decl) == PARM_DECL && !DECL_CONTEXT (decl))
     return;
 
-  /* External decls are something else.  */
-  if (DECL_EXTERNAL (decl))
-    return;
-
   tree old = NULL_TREE;
   cp_binding_level *old_scope = NULL;
   if (cxx_binding *binding = outer_binding (DECL_NAME (decl), NULL, true))
@@ -3130,11 +3126,9 @@  check_local_shadow (tree decl)
 	      && DECL_CONTEXT (old) == lambda_function (current_lambda_expr ())
 	      && TREE_CODE (old) == PARM_DECL
 	      && DECL_NAME (decl) != this_identifier)
-	    {
-	      error_at (DECL_SOURCE_LOCATION (old),
-			"lambda parameter %qD "
-			"previously declared as a capture", old);
-	    }
+	    error_at (DECL_SOURCE_LOCATION (old),
+		      "lambda parameter %qD "
+		      "previously declared as a capture", old);
 	  return;
 	}
       /* Don't complain if it's from an enclosing function.  */
@@ -3156,10 +3150,18 @@  check_local_shadow (tree decl)
 	     in the outermost block of the function definition.  */
 	  if (b->kind == sk_function_parms)
 	    {
-	      error_at (DECL_SOURCE_LOCATION (decl),
-			"declaration of %q#D shadows a parameter", decl);
-	      inform (DECL_SOURCE_LOCATION (old),
-		      "%q#D previously declared here", old);
+	      auto_diagnostic_group d;
+	      bool emit = true;
+	      if (DECL_EXTERNAL (decl))
+		emit = pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic,
+				"declaration of %q#D shadows a parameter",
+				decl);
+	      else
+		error_at (DECL_SOURCE_LOCATION (decl),
+			  "declaration of %q#D shadows a parameter", decl);
+	      if (emit)
+		inform (DECL_SOURCE_LOCATION (old),
+			"%q#D previously declared here", old);
 	      return;
 	    }
 	}
@@ -3185,10 +3187,16 @@  check_local_shadow (tree decl)
 	       && (old_scope->kind == sk_cond || old_scope->kind == sk_for))
 	{
 	  auto_diagnostic_group d;
-	  error_at (DECL_SOURCE_LOCATION (decl),
-		    "redeclaration of %q#D", decl);
-	  inform (DECL_SOURCE_LOCATION (old),
-		  "%q#D previously declared here", old);
+	  bool emit = true;
+	  if (DECL_EXTERNAL (decl))
+	    emit = pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic,
+			    "redeclaration of %q#D", decl);
+	  else
+	    error_at (DECL_SOURCE_LOCATION (decl),
+		      "redeclaration of %q#D", decl);
+	  if (emit)
+	    inform (DECL_SOURCE_LOCATION (old),
+		    "%q#D previously declared here", old);
 	  return;
 	}
       /* C++11:
@@ -3314,6 +3322,7 @@  check_local_shadow (tree decl)
 	  || (TREE_CODE (old) == TYPE_DECL
 	      && (!DECL_ARTIFICIAL (old)
 		  || TREE_CODE (decl) == TYPE_DECL)))
+      && !DECL_EXTERNAL (decl)
       && !instantiating_current_function_p ()
       && !warning_suppressed_p (decl, OPT_Wshadow))
     /* XXX shadow warnings in outer-more namespaces */
--- gcc/testsuite/g++.dg/diagnostic/redeclaration-4.C.jj	2023-09-01 10:46:15.646025458 +0200
+++ gcc/testsuite/g++.dg/diagnostic/redeclaration-4.C	2023-09-01 10:46:15.646025458 +0200
@@ -0,0 +1,167 @@ 
+// PR c++/52953
+// { dg-do compile }
+// { dg-options "-pedantic-errors -Wno-switch-unreachable" }
+
+void
+foo (int x)				// { dg-message "'int x' previously declared here" }
+{
+  extern int x;				// { dg-error "declaration of 'int x' shadows a parameter" }
+}
+
+void
+bar (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+  extern int x;				// { dg-error "declaration of 'int x' shadows a parameter" }
+}
+catch (...)
+{
+}
+
+volatile int v;
+
+void
+baz ()
+{
+#if __cplusplus >= 201103L
+  auto f = [] (int x) { extern 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" }
+    {
+      extern int x;			// { dg-error "redeclaration of 'int x'" }
+    }
+  if (int x = 0)			// { dg-message "'int x' previously declared here" }
+    ;
+  else
+    {
+      extern int x;			// { dg-error "redeclaration of 'int x'" }
+    }
+  if (int x = 1)			// { dg-message "'int x' previously declared here" }
+    extern int x;			// { dg-error "redeclaration of 'int x'" }
+  if (int x = 0)			// { dg-message "'int x' previously declared here" }
+    ;
+  else
+    extern int x;			// { dg-error "redeclaration of 'int x'" }
+  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
+    {
+      extern int x;			// { dg-error "redeclaration of 'int x'" }
+    default:;
+    }
+  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
+    extern int x;			// { dg-error "redeclaration of 'int x'" }
+  while (int x = v)
+    {
+      extern int x;			// { dg-error "'int x' conflicts with a previous declaration" }
+    }
+  while (int x = v)
+    extern int x;			// { dg-error "'int x' conflicts with a previous declaration" }
+  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
+    {
+      extern int x;			// { dg-error "redeclaration of 'int x'" }
+    }
+  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
+    extern int x;			// { dg-error "redeclaration of 'int x'" }
+  for (; int x = v; )
+    {
+      extern int x;			// { dg-error "'int x' conflicts with a previous declaration" }
+    }
+  for (; int x = v; )
+    extern int x;			// { dg-error "'int x' conflicts with a previous declaration" }
+  try
+    {
+    }
+  catch (int x)				// { dg-message "'int x' previously declared here" }
+    {
+      extern int x;			// { dg-error "redeclaration of 'int x'" }
+    }
+}
+
+void
+corge (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+}
+catch (...)
+{
+  extern int x;				// { dg-error "redeclaration of 'int x'" }
+}
+
+void
+fred (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+}
+catch (int)
+{
+}
+catch (long)
+{
+  extern int x;				// { dg-error "redeclaration of 'int x'" }
+}
+
+void
+garply (int x)
+{
+  try
+    {
+      extern int x;
+    }
+  catch (...)
+    {
+      extern int x;
+    }
+}
+
+struct S
+{
+  S (int x)				// { dg-message "'int x' previously declared here" }
+  try : s (x)
+  {
+    extern 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 (...)
+  {
+    extern int x;				// { dg-error "redeclaration of 'int x'" }
+  }
+  int t;
+};
+
+struct U
+{
+  U (int x) : u (x)
+  {
+    try
+    {
+      extern int x;
+    }
+    catch (...)
+    {
+      extern int x;
+    }
+  }
+  int u;
+};
+
+struct V
+{
+  V (int x) : v (x)
+  {
+    {
+      extern int x;
+    }
+  }
+  int v;
+};
--- gcc/testsuite/g++.dg/diagnostic/redeclaration-5.C.jj	2023-09-01 10:46:15.646025458 +0200
+++ gcc/testsuite/g++.dg/diagnostic/redeclaration-5.C	2023-09-01 10:46:15.646025458 +0200
@@ -0,0 +1,167 @@ 
+// PR c++/52953
+// { dg-do compile }
+// { dg-options "-pedantic-errors -Wno-switch-unreachable" }
+
+void
+foo (int x)				// { dg-message "'int x' previously declared here" }
+{
+  extern int x (int);			// { dg-error "declaration of 'int x\\\(int\\\)' shadows a parameter" }
+}
+
+void
+bar (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+  extern int x (int);			// { dg-error "declaration of 'int x\\\(int\\\)' shadows a parameter" }
+}
+catch (...)
+{
+}
+
+volatile int v;
+
+void
+baz ()
+{
+#if __cplusplus >= 201103L
+  auto f = [] (int x) { extern int x (int); };// { dg-error "declaration of 'int x\\\(int\\\)' 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" }
+    {
+      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+    }
+  if (int x = 0)			// { dg-message "'int x' previously declared here" }
+    ;
+  else
+    {
+      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+    }
+  if (int x = 1)			// { dg-message "'int x' previously declared here" }
+    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+  if (int x = 0)			// { dg-message "'int x' previously declared here" }
+    ;
+  else
+    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
+    {
+      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+    default:;
+    }
+  switch (int x = 1)			// { dg-message "'int x' previously declared here" }
+    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+  while (int x = v)
+    {
+      extern int x (int);		// { dg-error "'int x\\\(int\\\)' redeclared as different kind of entity" }
+    }
+  while (int x = v)
+    extern int x (int);			// { dg-error "'int x\\\(int\\\)' redeclared as different kind of entity" }
+  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
+    {
+      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+    }
+  for (int x = v; x; ++x)		// { dg-message "'int x' previously declared here" }
+    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+  for (; int x = v; )
+    {
+      extern int x (int);		// { dg-error "'int x\\\(int\\\)' redeclared as different kind of entity" }
+    }
+  for (; int x = v; )
+    extern int x (int);			// { dg-error "'int x\\\(int\\\)' redeclared as different kind of entity" }
+  try
+    {
+    }
+  catch (int x)				// { dg-message "'int x' previously declared here" }
+    {
+      extern int x (int);		// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+    }
+}
+
+void
+corge (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+}
+catch (...)
+{
+  extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+}
+
+void
+fred (int x)				// { dg-message "'int x' previously declared here" }
+try
+{
+}
+catch (int)
+{
+}
+catch (long)
+{
+  extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+}
+
+void
+garply (int x)
+{
+  try
+    {
+      extern int x (int);
+    }
+  catch (...)
+    {
+      extern int x (int);
+    }
+}
+
+struct S
+{
+  S (int x)				// { dg-message "'int x' previously declared here" }
+  try : s (x)
+  {
+    extern int x (int);			// { dg-error "declaration of 'int x\\\(int\\\)' shadows a parameter" }
+  }
+  catch (...)
+  {
+  }
+  int s;
+};
+
+struct T
+{
+  T (int x)				// { dg-message "'int x' previously declared here" }
+  try : t (x)
+  {
+  }
+  catch (...)
+  {
+    extern int x (int);			// { dg-error "redeclaration of 'int x\\\(int\\\)'" }
+  }
+  int t;
+};
+
+struct U
+{
+  U (int x) : u (x)
+  {
+    try
+    {
+      extern int x (int);
+    }
+    catch (...)
+    {
+      extern int x (int);
+    }
+  }
+  int u;
+};
+
+struct V
+{
+  V (int x) : v (x)
+  {
+    {
+      extern int x (int);
+    }
+  }
+  int v;
+};
--- gcc/testsuite/g++.dg/warn/Wshadow-19.C.jj	2023-09-01 11:35:21.092200057 +0200
+++ gcc/testsuite/g++.dg/warn/Wshadow-19.C	2023-09-01 11:37:15.997598483 +0200
@@ -0,0 +1,27 @@ 
+// { dg-do compile }
+// { dg-options "-Wshadow" }
+
+void
+foo (int x)
+{
+  int y = 1;
+  {
+    extern int x;				// { dg-warning "declaration of 'int x' shadows a parameter" }
+    extern int y;				// { dg-warning "declaration of 'y' shadows a previous local" }
+  }
+#if __cplusplus >= 201102L
+  auto fn = [x] () { extern int x; return 0; };	// { dg-warning "declaration of 'x' shadows a lambda capture" "" { target c++11 } }
+#endif
+}
+
+int z;
+
+struct S
+{
+  int x;
+  void foo ()
+  {
+    extern int x;				// { dg-warning "declaration of 'x' shadows a member of 'S'" }
+    extern int z;
+  }
+};