DR 2289 clarified that since structured bindings have no C compatibility
implications, they should be unique in their declarative region, see
[basic.scope.declarative]/4.2.
The duplicate_decls hunk is the gist of the patch, but that alone would
not be enough to detect the 'A' case: cp_parser_decomposition_declaration
uses
13968 tree decl2 = start_decl (declarator, &decl_specs, SD_INITIALIZED,
13969 NULL_TREE, NULL_TREE, &elt_pushed_scope);
to create the 'A' VAR_DECL but in this start_decl's grokdeclarator we
don't do fit_decomposition_lang_decl because the declarator kind is not
cdk_decomp, so then when start_decl calls maybe_push_decl, the decl 'A'
isn't DECL_DECOMPOSITION_P and we don't detect this case. So I needed a
way to signal to start_decl that it should fit_decomposition_lang_decl.
A simple flag seems the easiest solution.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
DR 2289
PR c++/94553
* cp-tree.h (groktypename): Fix formatting.
(start_decl): Add new bool parameter with a default argument.
* decl.c (duplicate_decls): Make sure a structured binding is unique
in its declarative region.
(start_decl): Add new bool parameter. If it's true, call
fit_decomposition_lang_decl.
* parser.c (cp_parser_decomposition_declaration): Pass true to
start_decl.
* g++.dg/cpp1z/decomp52.C: New test.
---
gcc/cp/cp-tree.h | 7 +++++--
gcc/cp/decl.c | 13 +++++++++++--
gcc/cp/parser.c | 3 ++-
gcc/testsuite/g++.dg/cpp1z/decomp52.C | 14 ++++++++++++++
4 files changed, 32 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp1z/decomp52.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f7c11bcf838..1f1f5b69313 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6525,8 +6525,11 @@ extern void warn_misplaced_attr_for_class_type
(location_t location,
tree class_type);
extern tree check_tag_decl (cp_decl_specifier_seq *, bool);
extern tree shadow_tag (cp_decl_specifier_seq *);
-extern tree groktypename (cp_decl_specifier_seq *, const
cp_declarator *, bool);
-extern tree start_decl (const cp_declarator *,
cp_decl_specifier_seq *, int, tree, tree, tree *);
+extern tree groktypename (cp_decl_specifier_seq *,
+ const cp_declarator *, bool);
+extern tree start_decl (const cp_declarator *,
+ cp_decl_specifier_seq *, int,
+ tree, tree, tree *, bool =
false);
extern void start_decl_1 (tree, bool);
extern bool check_array_initializer (tree, tree, tree);
extern void omp_declare_variant_finalize (tree, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 1b6a5672334..6464dbbfc99 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1705,6 +1705,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool
newdecl_is_friend)
inform (olddecl_loc, "previous declaration %q#D", olddecl);
return error_mark_node;
}
+ else if ((VAR_P (olddecl) && DECL_DECOMPOSITION_P (olddecl))
+ || (VAR_P (newdecl) && DECL_DECOMPOSITION_P (newdecl)))
+ /* A structured binding must be unique in its declarative region. */;
else if (DECL_IMPLICIT_TYPEDEF_P (olddecl)
|| DECL_IMPLICIT_TYPEDEF_P (newdecl))
/* One is an implicit typedef, that's ok. */
@@ -5199,7 +5202,8 @@ groktypename (cp_decl_specifier_seq *type_specifiers,
The scope represented by the context of the returned DECL is pushed
(if it is not the global namespace) and is assigned to
*PUSHED_SCOPE_P. The caller is then responsible for calling
- pop_scope on *PUSHED_SCOPE_P if it is set. */
+ pop_scope on *PUSHED_SCOPE_P if it is set. If FORCE_LANG_DECL_P, create
+ a lang decl node for the new decl. */
tree
start_decl (const cp_declarator *declarator,
@@ -5207,7 +5211,8 @@ start_decl (const cp_declarator *declarator,
int initialized,
tree attributes,
tree prefix_attributes,
- tree *pushed_scope_p)
+ tree *pushed_scope_p,
+ bool force_lang_decl_p/*=false*/)
{
tree decl;
tree context;
@@ -5387,6 +5392,10 @@ start_decl (const cp_declarator *declarator,
decl);
}
+ /* Create a DECL_LANG_SPECIFIC so that DECL_DECOMPOSITION_P works. */
+ if (force_lang_decl_p)
+ fit_decomposition_lang_decl (decl, NULL_TREE);
+
was_public = TREE_PUBLIC (decl);
/* Enter this declaration into the symbol table. Don't push the plain
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index f1ddef220fe..06d6a262699 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13976,7 +13976,8 @@ cp_parser_decomposition_declaration (cp_parser *parser,
}
tree elt_pushed_scope;
tree decl2 = start_decl (declarator, &decl_specs, SD_INITIALIZED,
- NULL_TREE, NULL_TREE, &elt_pushed_scope);
+ NULL_TREE, NULL_TREE, &elt_pushed_scope,
+ /*force_lang_decl_p=*/true);
if (decl2 == error_mark_node)
decl = error_mark_node;
else if (decl != error_mark_node && DECL_CHAIN (decl2) != prev)
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp52.C
b/gcc/testsuite/g++.dg/cpp1z/decomp52.C
new file mode 100644
index 00000000000..43b76181b5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp52.C
@@ -0,0 +1,14 @@
+// DR 2289
+// PR c++/94553
+// { dg-do compile { target c++17 } }
+// A structured binding must be unique in its declarative region.
+
+void
+f ()
+{
+ int arr[1] = { 1 };
+ struct A { };
+ auto [A] = arr; // { dg-error "redeclared as different kind of entity" }
+ auto [B] = arr;
+ struct B { }; // { dg-error "redeclared as different kind of entity" }
+}
base-commit: be99b308d0f88c72611f800bbe483dd2e1be248f
--
Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA