aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2022-05-25 18:11:31 -0400
committerMarek Polacek <polacek@redhat.com>2022-07-01 12:07:34 -0400
commitecd11acacd6be57af930fa617d7c31ecb40e7f74 (patch)
tree78da6f3fa4cbeec13ab2abf2b93d7a8c98015863 /gcc/cp
parent9a668532fb19e7c57aa595a26ce3f0d95f9cbb1b (diff)
downloadgcc-ecd11acacd6be57af930fa617d7c31ecb40e7f74.zip
gcc-ecd11acacd6be57af930fa617d7c31ecb40e7f74.tar.gz
gcc-ecd11acacd6be57af930fa617d7c31ecb40e7f74.tar.bz2
c++: fix broken copy elision with nested TARGET_EXPRs [PR105550]
In this problem, we are failing to properly perform copy elision with a conditional operator, so this: constexpr A a = true ? A{} : A{}; fails with: error: 'A{((const A*)(&<anonymous>))}' is not a constant expression The whole initializer is TARGET_EXPR <D.2395, 1 ? TARGET_EXPR <D.2393, {.p=(const struct A *) &<PLACEHOLDER_EXPR struct A>}> : TARGET_EXPR <D.2394, {.p=(const struct A *) &<PLACEHOLDER_EXPR struct A>}>> where the outermost TARGET_EXPR is elided, but not the nested ones. Then we end up replacing the PLACEHOLDER_EXPRs with the temporaries the TARGET_EXPRs represent, which is precisely what should *not* happen with copy elision. I've tried the approach of tweaking ctx->object, but I ran into gazillion problems with that. I thought that I would let cxx_eval_constant_expression /TARGET_EXPR create a new object only when ctx->object was null, then adjust setting of ctx->object in places like cxx_bind_parameters_in_call and cxx_eval_component_reference but that failed completely. Sometimes ctx->object has to be reset, sometimes it cannot be reset, 'this' needed special handling, etc. I gave up. Instead, this patch strips TARGET_EXPRs from the operands of ?: like we do in various other places in constexpr.c. PR c++/105550 gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_conditional_expression): Strip TARGET_EXPRs. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/nsdmi-aggr16.C: Remove FIXME. * g++.dg/cpp1y/nsdmi-aggr17.C: Remove FIXME. * g++.dg/cpp0x/constexpr-elision1.C: New test. * g++.dg/cpp1y/constexpr-elision1.C: New test.
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/constexpr.cc7
1 files changed, 7 insertions, 0 deletions
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 0dc94d9..5f7fc6f 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3507,6 +3507,13 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
val = TREE_OPERAND (t, 1);
if (TREE_CODE (t) == IF_STMT && !val)
val = void_node;
+ /* A TARGET_EXPR may be nested inside another TARGET_EXPR, but still
+ serve as the initializer for the same object as the outer TARGET_EXPR,
+ as in
+ A a = true ? A{} : A{};
+ so strip the inner TARGET_EXPR so we don't materialize a temporary. */
+ if (TREE_CODE (val) == TARGET_EXPR)
+ val = TARGET_EXPR_INITIAL (val);
return cxx_eval_constant_expression (ctx, val, lval, non_constant_p,
overflow_p, jump_target);
}