Hi! On the following testcase, build_conditional_expr_1 tries hard to make sure that if both arguments are xvalue_p (or one is and the other throw) the result is still xvalue_p. But, later on we call unary_complex_lvalue, which does rationalize_conditional_expr which changes it from cond ? x : y to *(cond ? &x : &y) and that change turns something formerly xvalue_p into newly lvalue_p.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2018-11-29 Jakub Jelinek <ja...@redhat.com> PR c++/88103 * typeck.c (unary_complex_lvalue): If a COND_EXPR is xvalue_p, make sure the result is as well. * g++.dg/cpp0x/rv-cond3.C: New test. --- gcc/cp/typeck.c.jj 2018-11-27 09:48:58.506103668 +0100 +++ gcc/cp/typeck.c 2018-11-29 21:00:33.900636750 +0100 @@ -6503,7 +6503,16 @@ unary_complex_lvalue (enum tree_code cod /* Handle (a ? b : c) used as an "lvalue". */ if (TREE_CODE (arg) == COND_EXPR || TREE_CODE (arg) == MIN_EXPR || TREE_CODE (arg) == MAX_EXPR) - return rationalize_conditional_expr (code, arg, tf_warning_or_error); + { + tree ret = rationalize_conditional_expr (code, arg, tf_warning_or_error); + /* Preserve xvalue kind. */ + if (xvalue_p (arg)) + { + tree reftype = cp_build_reference_type (TREE_TYPE (arg), true); + ret = cp_convert (reftype, ret, tf_warning_or_error); + } + return ret; + } /* Handle (a = b), (++a), and (--a) used as an "lvalue". */ if (TREE_CODE (arg) == MODIFY_EXPR --- gcc/testsuite/g++.dg/cpp0x/rv-cond3.C.jj 2018-11-29 21:04:48.228440774 +0100 +++ gcc/testsuite/g++.dg/cpp0x/rv-cond3.C 2018-11-29 21:06:22.315888491 +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