c++: constexpr aggr init of empty class [PR101040]

This is basically the aggregate initializer version of PR97566; as in that
bug, we are trying to initialize empty field 'obj' in 'single' when there's
no CONSTRUCTOR entry for the 'single' base class subobject of 'derived'.  As
with that bug, the fix is to stop trying to add entries for empty fields,
this time in cxx_eval_bare_aggregate.

The change to the other function isn't necessary for this version of
the patch, but seems worthwhile for robustness anyway.

	PR c++/101040
	PR c++/97566

gcc/cp/ChangeLog:

	* class.c (is_empty_field): Handle null argument.
	* constexpr.c (cxx_eval_bare_aggregate): Discard initializer
	for empty field.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/no_unique_address13.C: New test.
This commit is contained in:
Jason Merrill 2021-06-24 17:32:02 -04:00
parent 2afe882858
commit 2168bfb814
3 changed files with 33 additions and 2 deletions

View File

@ -4220,7 +4220,7 @@ field_poverlapping_p (tree decl)
bool
is_empty_field (tree decl)
{
if (TREE_CODE (decl) != FIELD_DECL)
if (!decl || TREE_CODE (decl) != FIELD_DECL)
return false;
bool r = (is_empty_class (TREE_TYPE (decl))

View File

@ -4449,7 +4449,12 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value)
{
tree orig_value = value;
init_subob_ctx (ctx, new_ctx, index, value);
/* Like in cxx_eval_store_expression, omit entries for empty fields. */
bool no_slot = TREE_CODE (type) == RECORD_TYPE && is_empty_field (index);
if (no_slot)
new_ctx = *ctx;
else
init_subob_ctx (ctx, new_ctx, index, value);
int pos_hint = -1;
if (new_ctx.ctor != ctx->ctor)
{
@ -4495,6 +4500,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index))));
changed = true;
}
else if (no_slot)
changed = true;
else
{
if (TREE_CODE (type) == UNION_TYPE

View File

@ -0,0 +1,24 @@
// PR c++/101040
// { dg-do compile { target c++11 } }
// This class has to be empty.
struct empty
{};
// This class has to be empty.
struct single
{
// This member has to be no_unique_address.
[[no_unique_address]] empty obj;
};
// This class has to be empty and derived from single.
struct derived : single
{
// This constructor has to be constexpr and take a forwarding reference.
template <typename Arg>
constexpr derived(Arg&& arg) : single{arg}
{}
};
auto obj = derived{empty{}};