[gcc(refs/users/guojiufu/heads/guojiufu-branch)] c++: Implement DR 2289, Uniqueness of structured binding names [PR94553]

Jiu Fu Guo guojiufu@gcc.gnu.org
Wed Jun 10 03:00:10 GMT 2020


https://gcc.gnu.org/g:2a8565fa1182ed326721a50c700f9f5275355d40

commit 2a8565fa1182ed326721a50c700f9f5275355d40
Author: Marek Polacek <polacek@redhat.com>
Date:   Tue May 19 23:53:28 2020 -0400

    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.

Diff:
---
 gcc/cp/ChangeLog                      | 13 +++++++++++++
 gcc/cp/cp-tree.h                      |  6 ++++--
 gcc/cp/decl.c                         | 27 +++++++++++++++++----------
 gcc/cp/parser.c                       |  2 +-
 gcc/testsuite/ChangeLog               |  6 ++++++
 gcc/testsuite/g++.dg/cpp1z/decomp52.C | 14 ++++++++++++++
 6 files changed, 55 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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9d04b2d4b14..9e437af7452 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2020-05-20  Marek Polacek  <polacek@redhat.com>
+
+	DR 2289
+	PR c++/94553
+	* g++.dg/cpp1z/decomp52.C: New test.
+
 2020-05-20  Uroš Bizjak  <ubizjak@gmail.com>
 
 	PR target/95229
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" }
+}


More information about the Gcc-cvs mailing list