]> gcc.gnu.org Git - gcc.git/commit
c++: ICE with temporary of class type in DMI [PR100252]
authorMarek Polacek <polacek@redhat.com>
Tue, 26 Apr 2022 19:52:00 +0000 (15:52 -0400)
committerMarek Polacek <polacek@redhat.com>
Wed, 25 May 2022 15:00:10 +0000 (11:00 -0400)
commit1b661f3f5e712c951e774b3b91fffe4dac734cc7
treef16ce49da86f56df90e8b80135becc8bb1d88f14
parent75c4e4909ae2667f56487434f99c2915b4570794
c++: ICE with temporary of class type in DMI [PR100252]

Consider

  struct A {
    int x;
    int y = x;
  };

  struct B {
    int x = 0;
    int y = A{x}.y; // #1
  };

where for #1 we end up with

  {.x=(&<PLACEHOLDER_EXPR struct B>)->x, .y=(&<PLACEHOLDER_EXPR struct A>)->x}

that is, two PLACEHOLDER_EXPRs for different types on the same level in
a {}.  This crashes because our CONSTRUCTOR_PLACEHOLDER_BOUNDARY mechanism to
avoid replacing unrelated PLACEHOLDER_EXPRs cannot deal with it.

Here's why we wound up with those PLACEHOLDER_EXPRs: When we're performing
cp_parser_late_parsing_nsdmi for "int y = A{x}.y;" we use finish_compound_literal
on type=A, compound_literal={((struct B *) this)->x}.  When digesting this
initializer, we call get_nsdmi which creates a PLACEHOLDER_EXPR for A -- we don't
have any object to refer to yet.  After digesting, we have

  {.x=((struct B *) this)->x, .y=(&<PLACEHOLDER_EXPR struct A>)->x}

and since we've created a PLACEHOLDER_EXPR inside it, we marked the whole ctor
CONSTRUCTOR_PLACEHOLDER_BOUNDARY.  f_c_l creates a TARGET_EXPR and returns

  TARGET_EXPR <D.2384, {.x=((struct B *) this)->x, .y=(&<PLACEHOLDER_EXPR struct A>)->x}>

Then we get to

  B b = {};

and call store_init_value, which digests the {}, which produces

  {.x=NON_LVALUE_EXPR <0>, .y=(TARGET_EXPR <D.2395, {.x=(&<PLACEHOLDER_EXPR struct B>)->x, .y=(&<PLACEHOLDER_EXPR struct A>)->x}>).y}

lookup_placeholder in constexpr won't find an object to replace the
PLACEHOLDER_EXPR for B, because ctx->object will be D.2395 of type A, and we
cannot search outward from D.2395 to find 'b'.

The call to replace_placeholders in store_init_value will not do anything:
we've marked the inner { } CONSTRUCTOR_PLACEHOLDER_BOUNDARY, and it's only
a sub-expression, so replace_placeholders does nothing, so the <P_E struct B>
stays even though now is the perfect time to replace it because we have an
object for it: 'b'.

Later, in cp_gimplify_init_expr the *expr_p is

  D.2395 = {.x=(&<PLACEHOLDER_EXPR struct B>)->x, .y=(&<PLACEHOLDER_EXPR struct A>)->x}

where D.2395 is of type A, but we crash because we hit <P_E struct B>, which
has a different type.

My idea was to replace <P_E struct A> with D.2384 after creating the
TARGET_EXPR because that means we have an object we can refer to.
Then clear CONSTRUCTOR_PLACEHOLDER_BOUNDARY because we no longer have
a PLACEHOLDER_EXPR in the {}.  Then store_init_value will be able to
replace <P_E struct B> with 'b', and we should be good to go.  We must
be careful not to break guaranteed copy elision, so this replacement
happens in digest_nsdmi_init where we can see the whole initializer,
and avoid replacing any placeholders in TARGET_EXPRs used in the context
of initialization/copy elision.  This is achieved via the new function
called potential_prvalue_result_of.

While fixing this problem, I found PR105550, thus the FIXMEs in the
tests.

PR c++/100252

gcc/cp/ChangeLog:

* typeck2.cc (potential_prvalue_result_of): New.
(replace_placeholders_for_class_temp_r): New.
(digest_nsdmi_init): Call it.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/nsdmi-aggr14.C: New test.
* g++.dg/cpp1y/nsdmi-aggr15.C: New test.
* g++.dg/cpp1y/nsdmi-aggr16.C: New test.
* g++.dg/cpp1y/nsdmi-aggr17.C: New test.
* g++.dg/cpp1y/nsdmi-aggr18.C: New test.
* g++.dg/cpp1y/nsdmi-aggr19.C: New test.
gcc/cp/typeck2.cc
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr19.C [new file with mode: 0644]
This page took 0.071675 seconds and 6 git commands to generate.