* constexpr.c (cxx_eval_store_expression): Delay target evaluation.

From-SVN: r272431
This commit is contained in:
Jason Merrill 2019-06-18 12:08:29 -04:00 committed by Jason Merrill
parent 043666e095
commit d0aa42d276
2 changed files with 37 additions and 16 deletions

View File

@ -1,3 +1,7 @@
2019-06-18 Jason Merrill <jason@redhat.com>
* constexpr.c (cxx_eval_store_expression): Delay target evaluation.
2019-06-18 Jason Merrill <jason@redhat.com>
* constexpr.c (eval_and_check_array_index): Split out from...

View File

@ -3747,22 +3747,18 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (*non_constant_p)
return t;
}
target = cxx_eval_constant_expression (ctx, target,
true,
non_constant_p, overflow_p);
if (*non_constant_p)
return t;
if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (target), type))
bool evaluated = false;
if (lval)
{
/* For initialization of an empty base, the original target will be
*(base*)this, which the above evaluation resolves to the object
argument, which has the derived type rather than the base type. In
this situation, just evaluate the initializer and return, since
there's no actual data to store. */
gcc_assert (is_empty_class (type));
return cxx_eval_constant_expression (ctx, init, false,
non_constant_p, overflow_p);
/* If we want to return a reference to the target, we need to evaluate it
as a whole; otherwise, only evaluate the innermost piece to avoid
building up unnecessary *_REFs. */
target = cxx_eval_constant_expression (ctx, target, true,
non_constant_p, overflow_p);
evaluated = true;
if (*non_constant_p)
return t;
}
/* Find the underlying variable. */
@ -3792,7 +3788,17 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
break;
default:
object = probe;
if (evaluated)
object = probe;
else
{
probe = cxx_eval_constant_expression (ctx, probe, true,
non_constant_p, overflow_p);
evaluated = true;
if (*non_constant_p)
return t;
}
break;
}
}
@ -3948,7 +3954,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
new_ctx.object = target;
init = cxx_eval_constant_expression (&new_ctx, init, false,
non_constant_p, overflow_p);
if (target == object)
if (ctors->is_empty())
/* The hash table might have moved since the get earlier. */
valp = ctx->values->get (object);
}
@ -3961,6 +3967,17 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
{
/* An outer ctx->ctor might be pointing to *valp, so replace
its contents. */
if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init),
TREE_TYPE (*valp)))
{
/* For initialization of an empty base, the original target will be
*(base*)this, evaluation of which resolves to the object
argument, which has the derived type rather than the base type. In
this situation, just evaluate the initializer and return, since
there's no actual data to store. */
gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval);
return init;
}
CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init);
TREE_CONSTANT (*valp) = TREE_CONSTANT (init);
TREE_SIDE_EFFECTS (*valp) = TREE_SIDE_EFFECTS (init);