From d0aa42d276497d762934da72d7ad6d3d4b5551fc Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 18 Jun 2019 12:08:29 -0400 Subject: [PATCH] * constexpr.c (cxx_eval_store_expression): Delay target evaluation. From-SVN: r272431 --- gcc/cp/ChangeLog | 4 ++++ gcc/cp/constexpr.c | 49 +++++++++++++++++++++++++++++++--------------- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1071a52a558..7bd47cf4b56 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2019-06-18 Jason Merrill + + * constexpr.c (cxx_eval_store_expression): Delay target evaluation. + 2019-06-18 Jason Merrill * constexpr.c (eval_and_check_array_index): Split out from... diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 7c733d78b5b..22f4fa0d351 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -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); -- 2.30.2