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" }
+}

Reply via email to