diff options
author | Patrick Palka <ppalka@redhat.com> | 2021-03-06 17:09:07 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2021-03-06 17:09:07 -0500 |
commit | d1bba463bd0d5692b7fa58ee37a61a55b2517456 (patch) | |
tree | be0148634d2c34eef8a04b6d29afa943ea11844e /gcc/cp | |
parent | 0cc54a68e309df89fb47bc1fa6c23662c45eeacc (diff) | |
download | gcc-d1bba463bd0d5692b7fa58ee37a61a55b2517456.zip gcc-d1bba463bd0d5692b7fa58ee37a61a55b2517456.tar.gz gcc-d1bba463bd0d5692b7fa58ee37a61a55b2517456.tar.bz2 |
c++: Fix constexpr evaluation of pre-increment when !lval [PR99287]
Here, during cxx_eval_increment_expression (with lval=false) of
++__first where __first is &"mystr"[0], we correctly update __first
to &"mystr"[1] but we end up returning &"mystr"[0] + 1 instead of
&"mystr"[1]. This unreduced return value inhibits other pointer
arithmetic folding during later constexpr evaluation, which ultimately
causes the constexpr evaluation to fail.
It turns out the simplification of &"mystr"[0] + 1 to &"mystr"[1]
is performed by cxx_fold_pointer_plus_expression, not by fold_build2.
So we perform this simplification during constexpr evaluation of
the temporary MODIFY_EXPR (during which we assign to __first the
simplified value), but then we return 'mod' which has only been folded
via fold_build2 and hasn't gone through cxx_fold_pointer_plus_expression.
This patch fixes this by updating 'mod' with the result of the
MODIFY_EXPR evaluation appropriately, so that it captures any additional
folding of the expression when !lval. We now need to be wary of this
evaluation failing and returning e.g. the MODIFY_EXPR or NULL_TREE; it
seems checking *non_constant_p should cover our bases here and is
generally prudent.
gcc/cp/ChangeLog:
PR c++/99287
* constexpr.c (cxx_eval_increment_expression): Pass lval when
evaluating the MODIFY_EXPR, and update 'mod' with the result of
this evaluation. Check *non_constant_p afterwards. For prefix
ops, just return 'mod'.
gcc/testsuite/ChangeLog:
PR c++/99287
* g++.dg/cpp2a/constexpr-99287.C: New test.
Co-authored-by: Jakub Jelinek <jakub@redhat.com>
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/constexpr.c | 17 |
1 files changed, 7 insertions, 10 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 7d96d57..c946744 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5582,20 +5582,17 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, /* Storing the modified value. */ tree store = build2_loc (cp_expr_loc_or_loc (t, input_location), MODIFY_EXPR, type, op, mod); - cxx_eval_constant_expression (ctx, store, - true, non_constant_p, overflow_p); + mod = cxx_eval_constant_expression (ctx, store, lval, + non_constant_p, overflow_p); ggc_free (store); + if (*non_constant_p) + return t; /* And the value of the expression. */ if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR) - { - /* Prefix ops are lvalues. */ - if (lval) - return op; - else - /* But we optimize when the caller wants an rvalue. */ - return mod; - } + /* Prefix ops are lvalues, but the caller might want an rvalue; + lval has already been taken into account in the store above. */ + return mod; else /* Postfix ops are rvalues. */ return val; |