c++: designated init with anonymous union [PR100489]

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.

	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.
This commit is contained in:
Jason Merrill 2021-05-19 21:12:45 -04:00
parent 64ba45c76e
commit 84fd1b5dff
3 changed files with 46 additions and 30 deletions

View file

@ -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. */

View file

@ -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)

View file

@ -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 };
}