https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100252

--- Comment #11 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The trunk branch has been updated by Marek Polacek <mpola...@gcc.gnu.org>:

https://gcc.gnu.org/g:1b661f3f5e712c951e774b3b91fffe4dac734cc7

commit r13-765-g1b661f3f5e712c951e774b3b91fffe4dac734cc7
Author: Marek Polacek <pola...@redhat.com>
Date:   Tue Apr 26 15:52:00 2022 -0400

    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.

Reply via email to