On Mon, Dec 03, 2018 at 02:44:32PM -0500, Jason Merrill wrote: > > > Is there a reason not to use the 'move' function here? > > > > That doesn't work at all. move doesn't call cp_convert, but > > build_static_cast (though for the same reference && type). > > But while cp_convert only adds NOP_EXPR around it, build_static_cast adds > > a target_expr, addr_expr around that, nop_expr cast to the reference && type > > and finally indirect_ref that the caller doesn't expect, because it adds it > > by itself, e.g. in > > 2424 if (temp) > > 2425 object = cp_build_fold_indirect_ref (temp); > > So the caller is trying to take the address of the COND_EXPR, which should > have POINTER_TYPE. And then indirecting that gives an lvalue, as it should. > The bug is in the caller, build_class_member_access_expr.
So like this then (if it passes bootstrap/regtest)? Seems to fix the testcase. 2018-12-03 Jakub Jelinek <ja...@redhat.com> PR c++/88103 * typeck.c (build_class_member_access_expr): If unary_complex_lvalue turned xvalue_p into non-xvalue_p, call move on it. * g++.dg/cpp0x/rv-cond3.C: New test. --- gcc/cp/typeck.c.jj 2018-12-02 21:41:09.824475721 +0100 +++ gcc/cp/typeck.c 2018-12-03 22:06:04.425357227 +0100 @@ -2422,7 +2422,13 @@ build_class_member_access_expr (cp_expr { tree temp = unary_complex_lvalue (ADDR_EXPR, object); if (temp) - object = cp_build_fold_indirect_ref (temp); + { + temp = cp_build_fold_indirect_ref (temp); + if (xvalue_p (object) && !xvalue_p (temp)) + /* Preserve xvalue kind. */ + temp = move (temp); + object = temp; + } } /* In [expr.ref], there is an explicit list of the valid choices for --- gcc/testsuite/g++.dg/cpp0x/rv-cond3.C.jj 2018-12-03 22:04:14.064144468 +0100 +++ gcc/testsuite/g++.dg/cpp0x/rv-cond3.C 2018-12-03 22:04:14.064144468 +0100 @@ -0,0 +1,22 @@ +// PR c++/88103 +// { dg-do compile { target c++11 } } + +struct A { + A (int); + A&& foo () &&; + int i; +}; +void free (A&&); + +void test_xvalue (A a){ + A&& ref = true ? static_cast<A&&> (a) : static_cast<A&&> (a); + free (true ? static_cast<A&&> (a) : static_cast<A&&> (a)); + (true ? static_cast<A&&> (a) : static_cast<A&&> (a)).foo (); + int&& k = (true ? static_cast<A&&> (a) : static_cast<A&&> (a)).i; +} +void test_prvalue (A a){ + A&& ref = true ? static_cast<A&&> (a) : 1; + free (true ? static_cast<A&&> (a) : 1); + (true ? static_cast<A&&> (a) : 1).foo (); + int&& k = (true ? static_cast<A&&> (a) : 1).i; +} Jakub