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.