[PATCH v2] c++: Implement DR 2289, Uniqueness of structured binding names [PR94553]
Marek Polacek
polacek@redhat.com
Wed May 20 05:14:40 GMT 2020
On Tue, May 19, 2020 at 10:39:59AM -0400, Jason Merrill wrote:
> On 5/18/20 5:07 PM, Marek Polacek wrote:
> > On Mon, May 18, 2020 at 04:50:44PM -0400, Jason Merrill via Gcc-patches wrote:
> > > On 5/13/20 12:22 PM, Marek Polacek wrote:
> > > > 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
> > >
> > > Why isn't it? I see
> > >
> > > cp_declarator *declarator = make_declarator (cdk_decomp);
> > >
> > > a few lines up.
> >
> > Right, and we use that for the underlying decomp base VAR_DECL. But each of
> > the named variables used in a structured binding are created in the
> > FOR_EACH_VEC_ELT loop, and that creates a cdk_id declarator for them:
> >
> > 13963 if (i == 0)
> > 13964 declarator = make_id_declarator (NULL_TREE, e.get_value (),
> > 13965 sfk_none, e.get_location ());
>
> Ah, yes.
>
> You name the new parameter FORCE_LANG_DECL_P and describe it as meaning
> "create a lang decl node for the new decl", but the actual meaning seems to
> be "mark the new decl as DECL_DECOMPOSITION_P", which seems too specific for
> adding a new parameter to a frequently used function.
>
> How about adding a new SD_DECOMPOSITION value for the initialized parameter,
> or an attribute?
Sounds good, I agree that a new SD_ flag is better than adding a new parameter
for such a corner case.
I've reviewed the uses of the 'initialized' parameter in start_decl{,1},
grokdeclarator, and grokvardecl and adjusted where needed. It's kind of
tempting to use an enum (possibly scoped one, now that we're in C++11)
instead of a #define but I've resisted doing that thus far.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
Thanks,
-- >8 --
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.
In this patch, I'm adding SD_DECOMPOSITION flag to say that the variable
is initialized and it should also be marked as DECL_DECOMPOSITION_P.
DR 2289
PR c++/94553
* cp-tree.h (SD_DECOMPOSITION): New flag.
* decl.c (duplicate_decls): Make sure a structured binding is unique
in its declarative region.
(start_decl): If INITIALIZED is SD_DECOMPOSITION, call
fit_decomposition_lang_decl.
(grokdeclarator): Compare INITIALIZED directly to SD_* flags.
* parser.c (cp_parser_decomposition_declaration): Pass SD_DECOMPOSITION
to start_decl.
* g++.dg/cpp1z/decomp52.C: New test.
---
gcc/cp/cp-tree.h | 6 ++++--
gcc/cp/decl.c | 23 +++++++++++++++++------
gcc/cp/parser.c | 2 +-
gcc/testsuite/g++.dg/cpp1z/decomp52.C | 14 ++++++++++++++
4 files changed, 36 insertions(+), 9 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 31c30ff87b3..27707abaadc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5694,8 +5694,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
/* Used with start_decl's initialized parameter. */
#define SD_UNINITIALIZED 0
#define SD_INITIALIZED 1
-#define SD_DEFAULTED 2
-#define SD_DELETED 3
+/* Like SD_INITIALIZED, but also mark the new decl as DECL_DECOMPOSITION_P. */
+#define SD_DECOMPOSITION 2
+#define SD_DEFAULTED 3
+#define SD_DELETED 4
/* Returns nonzero iff TYPE1 and TYPE2 are the same type, or if TYPE2
is derived from TYPE1, or if TYPE2 is a pointer (reference) to a
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 6469850e2dc..b64fb3fe716 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. */
@@ -5190,13 +5193,17 @@ groktypename (cp_decl_specifier_seq *type_specifiers,
declarations appearing in the body of the class go through
grokfield.) The DECL corresponding to the DECLARATOR is returned.
If an error occurs, the error_mark_node is returned instead.
-
+
DECLSPECS are the decl-specifiers for the declaration. INITIALIZED is
SD_INITIALIZED if an explicit initializer is present, or SD_DEFAULTED
for an explicitly defaulted function, or SD_DELETED for an explicitly
deleted function, but 0 (SD_UNINITIALIZED) if this is a variable
- implicitly initialized via a default constructor. ATTRIBUTES and
- PREFIX_ATTRIBUTES are GNU attributes associated with this declaration.
+ implicitly initialized via a default constructor. It can also be
+ SD_DECOMPOSITION which behaves much like SD_INITIALIZED, but we also
+ mark the new decl as DECL_DECOMPOSITION_P.
+
+ ATTRIBUTES and PREFIX_ATTRIBUTES are GNU attributes associated with this
+ declaration.
The scope represented by the context of the returned DECL is pushed
(if it is not the global namespace) and is assigned to
@@ -5233,7 +5240,7 @@ start_decl (const cp_declarator *declarator,
*pushed_scope_p = push_scope (context);
/* Is it valid for this decl to have an initializer at all?
- If not, set INITIALIZED to zero, which will indirectly
+ If not, return error_mark_node, which will indirectly
tell `cp_finish_decl' to ignore the initializer once it is parsed. */
if (initialized
&& TREE_CODE (decl) == TYPE_DECL)
@@ -5389,6 +5396,10 @@ start_decl (const cp_declarator *declarator,
decl);
}
+ /* Create a DECL_LANG_SPECIFIC so that DECL_DECOMPOSITION_P works. */
+ if (initialized == SD_DECOMPOSITION)
+ fit_decomposition_lang_decl (decl, NULL_TREE);
+
was_public = TREE_PUBLIC (decl);
/* Enter this declaration into the symbol table. Don't push the plain
@@ -10997,7 +11008,7 @@ grokdeclarator (const cp_declarator *declarator,
else if (decl_context == TPARM)
template_parm_flag = true, decl_context = PARM;
- if (initialized > 1)
+ if (initialized == SD_DEFAULTED || initialized == SD_DELETED)
funcdef_flag = true;
location_t typespec_loc = smallest_type_location (type_quals,
@@ -13304,7 +13315,7 @@ grokdeclarator (const cp_declarator *declarator,
|| (!dependent_type_p (type)
&& !COMPLETE_TYPE_P (complete_type (type))
&& (!complete_or_array_type_p (type)
- || initialized == 0))))
+ || initialized == SD_UNINITIALIZED))))
{
if (TREE_CODE (type) != ARRAY_TYPE
|| !COMPLETE_TYPE_P (TREE_TYPE (type)))
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e944841f5a3..a6a5d975af3 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13974,7 +13974,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
declarator->id_loc = e.get_location ();
}
tree elt_pushed_scope;
- tree decl2 = start_decl (declarator, &decl_specs, SD_INITIALIZED,
+ tree decl2 = start_decl (declarator, &decl_specs, SD_DECOMPOSITION,
NULL_TREE, NULL_TREE, &elt_pushed_scope);
if (decl2 == error_mark_node)
decl = error_mark_node;
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: b17a002ef579ed85edbe2c241222bfd0a86682db
--
Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA
More information about the Gcc-patches
mailing list