Another case where we weren't respecting the [class.copy.elision]/3 rule that "if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue." In this case the types differ because of the derived-to-base conversion. As a result, we chose the wrong ctor.
It seems that if we set rvaluedness_matches_p for ck_base, build_over_call then correctly returns error_mark_node for such ctor, because if sees that the CONVERSION_RANK is unsuitable. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2018-09-06 Marek Polacek <pola...@redhat.com> PR c++/87150 - wrong ctor with maybe-rvalue semantics. * call.c (struct conversion): Update commentary. (standard_conversion): Set rvaluedness_matches_p if LOOKUP_PREFER_RVALUE for ck_base. * g++.dg/cpp0x/move-return2.C: New test. diff --git gcc/cp/call.c gcc/cp/call.c index 942b2c204be..03b4c5ab224 100644 --- gcc/cp/call.c +++ gcc/cp/call.c @@ -102,10 +102,10 @@ struct conversion { BOOL_BITFIELD base_p : 1; /* If KIND is ck_ref_bind, true when either an lvalue reference is being bound to an lvalue expression or an rvalue reference is - being bound to an rvalue expression. If KIND is ck_rvalue, + being bound to an rvalue expression. If KIND is ck_rvalue or ck_base, true when we are treating an lvalue as an rvalue (12.8p33). If - KIND is ck_base, always false. If ck_identity, we will be - binding a reference directly or decaying to a pointer. */ + ck_identity, we will be binding a reference directly or decaying to + a pointer. */ BOOL_BITFIELD rvaluedness_matches_p: 1; BOOL_BITFIELD check_narrowing: 1; /* Whether check_narrowing should only check TREE_CONSTANTs; used @@ -1425,6 +1425,9 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, type. A temporary object is created to hold the result of the conversion unless we're binding directly to a reference. */ conv->need_temporary_p = !(flags & LOOKUP_NO_TEMP_BIND); + if (flags & LOOKUP_PREFER_RVALUE) + /* Tell convert_like_real to set LOOKUP_PREFER_RVALUE. */ + conv->rvaluedness_matches_p = true; } else return NULL; diff --git gcc/testsuite/g++.dg/cpp0x/move-return2.C gcc/testsuite/g++.dg/cpp0x/move-return2.C index e69de29bb2d..681e9ecaca1 100644 --- gcc/testsuite/g++.dg/cpp0x/move-return2.C +++ gcc/testsuite/g++.dg/cpp0x/move-return2.C @@ -0,0 +1,11 @@ +// PR c++/87150 +// { dg-do compile { target c++11 } } + +struct S1 { S1(S1 &&); }; +struct S2 : S1 {}; + +S1 +f (S2 s) +{ + return s; // { dg-error "use of deleted function" } +}