c++: fix broken copy elision with nested TARGET_EXPRs [PR105550]
commitecd11acacd6be57af930fa617d7c31ecb40e7f74
authorMarek Polacek <polacek@redhat.com>
Wed, 25 May 2022 22:11:31 +0000 (25 18:11 -0400)
committerMarek Polacek <polacek@redhat.com>
Fri, 1 Jul 2022 16:07:34 +0000 (1 12:07 -0400)
tree78da6f3fa4cbeec13ab2abf2b93d7a8c98015863
parent9a668532fb19e7c57aa595a26ce3f0d95f9cbb1b
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.
gcc/cp/constexpr.cc
gcc/testsuite/g++.dg/cpp0x/constexpr-elision1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/constexpr-elision1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C