c++: Diagnose [basic.scope.block]/2 violations even in compound-stmt of function-try-block [PR52953]
Checks
Commit Message
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
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
@@ -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;
@@ -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. */
@@ -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;
@@ -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;
+};