summaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2020-05-19 23:53:28 -0400
committerMarek Polacek <polacek@redhat.com>2020-05-20 13:35:09 -0400
commit2a8565fa1182ed326721a50c700f9f5275355d40 (patch)
tree5262a6749e233eacb317bbb259ac1e4c6d577f60 /gcc/cp
parent3872a519c8fa65318efa1b481d331ef91b3ff044 (diff)
c++: Implement DR 2289, Uniqueness of structured binding names [PR94553]
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.
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/cp-tree.h6
-rw-r--r--gcc/cp/decl.c27
-rw-r--r--gcc/cp/parser.c2
4 files changed, 35 insertions, 13 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c59137faa3f..9ed4c58b403 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,16 @@
+2020-05-20 Marek Polacek <polacek@redhat.com>
+
+ 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.
+
2020-05-20 Patrick Palka <ppalka@redhat.com>
PR c++/95223
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..024ddc88a4c 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
@@ -5232,11 +5239,7 @@ start_decl (const cp_declarator *declarator,
if (context != global_namespace)
*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
- tell `cp_finish_decl' to ignore the initializer once it is parsed. */
- if (initialized
- && TREE_CODE (decl) == TYPE_DECL)
+ if (initialized && TREE_CODE (decl) == TYPE_DECL)
{
error_at (DECL_SOURCE_LOCATION (decl),
"typedef %qD is initialized (use %qs instead)",
@@ -5389,6 +5392,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 +11004,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 +13311,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;