My patch for PR98463 added an assert that tripped on this testcase, because
we ended up with a U CONSTRUCTOR with an initializer for a, which is not a
member of U.  We need to wrap the a initializer in another CONSTRUCTOR for
the anonymous union.

There was already support for this in process_init_constructor_record, but
not in process_init_constructor_union.  But since this is about brace
elision, it really belongs under reshape_init rather than digest_init, so
this patch moves the handling to reshape_init_class, which also handles
unions.

Tested x86_64-pc-linux-gnu, applying to trunk.

        PR c++/100489

gcc/cp/ChangeLog:

        * decl.c (reshape_init_class): Handle designator for
        member of anonymous aggregate here.
        * typeck2.c (process_init_constructor_record): Not here.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/desig18.C: New test.
---
 gcc/cp/decl.c                        | 33 ++++++++++++++++++++++++----
 gcc/cp/typeck2.c                     | 26 ----------------------
 gcc/testsuite/g++.dg/cpp2a/desig18.C | 17 ++++++++++++++
 3 files changed, 46 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig18.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 28052df9f45..8a54e569041 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6418,10 +6418,9 @@ reshape_init_class (tree type, reshape_iter *d, bool 
first_initializer_p,
              /* We already reshaped this.  */
              if (field != d->cur->index)
                {
-                 tree id = DECL_NAME (d->cur->index);
-                 gcc_assert (id);
-                 gcc_checking_assert (d->cur->index
-                                      == get_class_binding (type, id));
+                 if (tree id = DECL_NAME (d->cur->index))
+                   gcc_checking_assert (d->cur->index
+                                        == get_class_binding (type, id));
                  field = d->cur->index;
                }
            }
@@ -6442,6 +6441,32 @@ reshape_init_class (tree type, reshape_iter *d, bool 
first_initializer_p,
                       d->cur->index);
              return error_mark_node;
            }
+
+         /* If the element is an anonymous union object and the initializer
+            list is a designated-initializer-list, the anonymous union object
+            is initialized by the designated-initializer-list { D }, where D
+            is the designated-initializer-clause naming a member of the
+            anonymous union object.  */
+         tree ictx = DECL_CONTEXT (field);
+         if (!same_type_ignoring_top_level_qualifiers_p (ictx, type))
+           {
+             gcc_assert (ANON_AGGR_TYPE_P (ictx));
+             /* Find the anon aggr that is a direct member of TYPE.  */
+             while (true)
+               {
+                 tree cctx = TYPE_CONTEXT (ictx);
+                 if (same_type_ignoring_top_level_qualifiers_p (cctx, type))
+                   break;
+                 ictx = cctx;
+               }
+             /* And then the TYPE member with that anon aggr type.  */
+             tree aafield = TYPE_FIELDS (type);
+             for (; aafield; aafield = TREE_CHAIN (aafield))
+               if (TREE_TYPE (aafield) == ictx)
+                 break;
+             gcc_assert (aafield);
+             field = aafield;
+           }
        }
 
       /* If we processed all the member of the class, we are done.  */
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index ce3016c780d..5a7219dec65 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1517,19 +1517,6 @@ process_init_constructor_record (tree type, tree init, 
int nested, int flags,
                          || identifier_p (ce->index));
              if (ce->index == field || ce->index == DECL_NAME (field))
                next = ce->value;
-             else if (ANON_AGGR_TYPE_P (fldtype)
-                      && search_anon_aggr (fldtype,
-                                           TREE_CODE (ce->index) == FIELD_DECL
-                                           ? DECL_NAME (ce->index)
-                                           : ce->index))
-               /* If the element is an anonymous union object and the
-                  initializer list is a designated-initializer-list, the
-                  anonymous union object is initialized by the
-                  designated-initializer-list { D }, where D is the
-                  designated-initializer-clause naming a member of the
-                  anonymous union object.  */
-               next = build_constructor_single (init_list_type_node,
-                                                ce->index, ce->value);
              else
                {
                  ce = NULL;
@@ -1675,19 +1662,6 @@ process_init_constructor_record (tree type, tree init, 
int nested, int flags,
 
                  if (ce->index == field || ce->index == DECL_NAME (field))
                    break;
-                 if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
-                   {
-                     tree t
-                       = search_anon_aggr (TREE_TYPE (field),
-                                           TREE_CODE (ce->index) == FIELD_DECL
-                                           ? DECL_NAME (ce->index)
-                                           : ce->index);
-                     if (t)
-                       {
-                         field = t;
-                         break;
-                       }
-                   }
                }
            }
          if (field)
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig18.C 
b/gcc/testsuite/g++.dg/cpp2a/desig18.C
new file mode 100644
index 00000000000..4851579b7c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/desig18.C
@@ -0,0 +1,17 @@
+// PR c++/100489
+// { dg-options "" }
+
+union U
+{
+  union
+  {
+    unsigned char a;
+  };
+
+  unsigned char b[1];
+};
+
+void f(unsigned char a)
+{
+  union U u = { .a = a };
+}

base-commit: 507359e1d4d18614eb9679043995edf0675b6ff5
-- 
2.27.0

Reply via email to