aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2019-06-18 12:08:29 -0400
committerJason Merrill <jason@gcc.gnu.org>2019-06-18 12:08:29 -0400
commitd0aa42d276497d762934da72d7ad6d3d4b5551fc (patch)
tree19dfd17c9aa5d02407078e9c1bc4455940fd9676
parent043666e0955d64ed538f2a5511f9fdc5484b657a (diff)
downloadgcc-d0aa42d276497d762934da72d7ad6d3d4b5551fc.zip
gcc-d0aa42d276497d762934da72d7ad6d3d4b5551fc.tar.gz
gcc-d0aa42d276497d762934da72d7ad6d3d4b5551fc.tar.bz2
* constexpr.c (cxx_eval_store_expression): Delay target evaluation.
From-SVN: r272431
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/constexpr.c49
2 files changed, 37 insertions, 16 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 1071a52..7bd47cf 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,9 @@
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...
(cxx_eval_array_reference): ...here.
(cxx_eval_store_expression): Use it here, too.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 7c733d7..22f4fa0 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);