aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2023-09-05 17:26:59 +0200
committerJakub Jelinek <jakub@redhat.com>2023-09-05 17:26:59 +0200
commitc24982689b8af19da9a64f2283fb99764a1c5db0 (patch)
tree017b63e4d4661390c270698def251576e8aeecde
parente87212ead5e9f36945b5e2d290187e2adca34da5 (diff)
downloadgcc-c24982689b8af19da9a64f2283fb99764a1c5db0.zip
gcc-c24982689b8af19da9a64f2283fb99764a1c5db0.tar.gz
gcc-c24982689b8af19da9a64f2283fb99764a1c5db0.tar.bz2
c++: Diagnose [basic.scope.block]/2 violations even in compound-stmt of function-try-block [PR52953]
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 in_function_try_handler case doesn't work correctly void foo (int x) try { } catch (int) { try { } catch (int x) { } try { } catch (int) { int x; } } (which is valid) is rejected, because || (TREE_CODE (old) == PARM_DECL && (current_binding_level->kind == sk_catch || current_binding_level->level_chain->kind == sk_catch) && in_function_try_handler)) is true but nothing verified that for the first case current_binding_level->level_chain->kind == sk_function_params (with perhaps artificial scopes in between and in the latter case with one extra level in between). The patch also changes behavior where for catch handlers of function-try-block the diagnostics will have the shadows function parameter wording as pedwarn rather than the old redeclaration permerror. 2023-09-05 Jakub Jelinek <jakub@redhat.com> PR c++/52953 * name-lookup.h (struct cp_binding_level): Add artificial bit-field. Formatting fixes. * name-lookup.cc (check_local_shadow): Skip artificial bindings when checking if parameter scope is parent scope. Don't special case FUNCTION_NEEDS_BODY_BLOCK. Diagnose the in_function_try_handler cases in the b->kind == sk_function_parms test and verify no non-artificial intervening scopes. Add missing auto_diagnostic_group. * decl.cc (begin_function_body): Set current_binding_level->artificial. * semantics.cc (begin_function_try_block): Likewise. * g++.dg/diagnostic/redeclaration-1.C: Expect different diagnostic wording. * g++.dg/diagnostic/redeclaration-3.C: New test. * g++.dg/parse/pr31952-1.C: Expect different diagnostic wording. * g++.dg/parse/pr31952-3.C: Likewise.
-rw-r--r--gcc/cp/decl.cc1
-rw-r--r--gcc/cp/name-lookup.cc25
-rw-r--r--gcc/cp/name-lookup.h12
-rw-r--r--gcc/cp/semantics.cc1
-rw-r--r--gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C2
-rw-r--r--gcc/testsuite/g++.dg/diagnostic/redeclaration-3.C225
-rw-r--r--gcc/testsuite/g++.dg/parse/pr31952-1.C2
-rw-r--r--gcc/testsuite/g++.dg/parse/pr31952-3.C2
8 files changed, 250 insertions, 20 deletions
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 89e8b85..255c402 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -18002,6 +18002,7 @@ begin_function_body (void)
keep_next_level (true);
tree stmt = begin_compound_stmt (BCS_FN_BODY);
+ current_binding_level->artificial = 1;
if (processing_template_decl)
/* Do nothing now. */;
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 2d74756..a2bcd4f 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3146,14 +3146,20 @@ check_local_shadow (tree decl)
them there. */
cp_binding_level *b = current_binding_level->level_chain;
- if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl))
- /* Skip the ctor/dtor cleanup level. */
+ if (in_function_try_handler && b->kind == sk_catch)
+ b = b->level_chain;
+
+ /* Skip artificially added scopes which aren't present
+ in the C++ standard, e.g. for function-try-block or
+ ctor/dtor cleanups. */
+ while (b->artificial)
b = b->level_chain;
/* [basic.scope.param] A parameter name shall not be redeclared
in the outermost block of the function definition. */
if (b->kind == sk_function_parms)
{
+ auto_diagnostic_group d;
error_at (DECL_SOURCE_LOCATION (decl),
"declaration of %q#D shadows a parameter", decl);
inform (DECL_SOURCE_LOCATION (old),
@@ -3194,17 +3200,10 @@ check_local_shadow (tree decl)
shall not be redeclared in the outermost block of the handler.
3.3.3/2: A parameter name shall not be redeclared (...) in
the outermost block of any handler associated with a
- function-try-block.
- 3.4.1/15: The function parameter names shall not be redeclared
- in the exception-declaration nor in the outermost block of a
- handler for the function-try-block. */
- else if ((TREE_CODE (old) == VAR_DECL
- && old_scope == current_binding_level->level_chain
- && old_scope->kind == sk_catch)
- || (TREE_CODE (old) == PARM_DECL
- && (current_binding_level->kind == sk_catch
- || current_binding_level->level_chain->kind == sk_catch)
- && in_function_try_handler))
+ function-try-block. */
+ else if (TREE_CODE (old) == VAR_DECL
+ && old_scope == current_binding_level->level_chain
+ && old_scope->kind == sk_catch)
{
auto_diagnostic_group d;
if (permerror (DECL_SOURCE_LOCATION (decl),
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 613745b..14e7915 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -292,11 +292,11 @@ struct GTY(()) cp_binding_level {
only valid if KIND == SK_TEMPLATE_PARMS. */
BOOL_BITFIELD explicit_spec_p : 1;
- /* true means make a BLOCK for this level regardless of all else. */
+ /* True means make a BLOCK for this level regardless of all else. */
unsigned keep : 1;
/* Nonzero if this level can safely have additional
- cleanup-needing variables added to it. */
+ cleanup-needing variables added to it. */
unsigned more_cleanups_ok : 1;
unsigned have_cleanups : 1;
@@ -308,9 +308,13 @@ struct GTY(()) cp_binding_level {
unsigned defining_class_p : 1;
/* True for SK_FUNCTION_PARMS of a requires-expression. */
- unsigned requires_expression: 1;
+ unsigned requires_expression : 1;
- /* 22 bits left to fill a 32-bit word. */
+ /* True for artificial blocks which should be ignored when finding
+ parent scope. */
+ unsigned artificial : 1;
+
+ /* 21 bits left to fill a 32-bit word. */
};
/* The binding level currently in effect. */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5b539ce..0f7f4e8 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -1624,6 +1624,7 @@ begin_function_try_block (tree *compound_stmt)
/* This outer scope does not exist in the C++ standard, but we need
a place to put __FUNCTION__ and similar variables. */
*compound_stmt = begin_compound_stmt (0);
+ current_binding_level->artificial = 1;
r = begin_try_block ();
FN_TRY_BLOCK_P (r) = 1;
return r;
diff --git a/gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C b/gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C
index f0e43d4..515fa39 100644
--- a/gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C
+++ b/gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C
@@ -15,6 +15,6 @@ bar (int i) // { dg-message "10:.int i. previously declared here" }
{ }
catch (...)
{
- int i // { dg-error "11:redeclaration of .int i." }
+ int i // { dg-error "11:declaration of .int i. shadows a parameter" }
(0);
}
diff --git a/gcc/testsuite/g++.dg/diagnostic/redeclaration-3.C b/gcc/testsuite/g++.dg/diagnostic/redeclaration-3.C
new file mode 100644
index 0000000..0934431
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/redeclaration-3.C
@@ -0,0 +1,225 @@
+// 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 "declaration of 'int x' shadows a parameter" }
+{
+}
+
+void
+corge (int x) // { dg-message "'int x' previously declared here" }
+try
+{
+}
+catch (...)
+{
+ int x; // { dg-error "declaration of 'int x' shadows a parameter" }
+}
+
+void
+fred (int x) // { dg-message "'int x' previously declared here" }
+try
+{
+}
+catch (int)
+{
+}
+catch (long)
+{
+ int x; // { dg-error "declaration of 'int x' shadows a parameter" }
+}
+
+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 "declaration of 'int x' shadows a parameter" }
+ }
+ 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;
+};
+
+void
+foobar (int x)
+try
+{
+}
+catch (int)
+{
+ try
+ {
+ }
+ catch (int x)
+ {
+ }
+ try
+ {
+ } catch (int)
+ {
+ int x;
+ }
+}
diff --git a/gcc/testsuite/g++.dg/parse/pr31952-1.C b/gcc/testsuite/g++.dg/parse/pr31952-1.C
index aad3a11..bae4713 100644
--- a/gcc/testsuite/g++.dg/parse/pr31952-1.C
+++ b/gcc/testsuite/g++.dg/parse/pr31952-1.C
@@ -8,7 +8,7 @@ try
}
catch (...)
{
- int bar = 0; // { dg-error "redeclaration" }
+ int bar = 0; // { dg-error "shadows a parameter" }
return 1;
}
diff --git a/gcc/testsuite/g++.dg/parse/pr31952-3.C b/gcc/testsuite/g++.dg/parse/pr31952-3.C
index 9fe5f02..b589097 100644
--- a/gcc/testsuite/g++.dg/parse/pr31952-3.C
+++ b/gcc/testsuite/g++.dg/parse/pr31952-3.C
@@ -6,7 +6,7 @@ try
{
return 0;
}
-catch (int bar) // { dg-error "redeclaration" }
+catch (int bar) // { dg-error "shadows a parameter" }
{
return 1;
}