This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH for c++/59823 (wrong overload resolution)/DR 1138


In the original testcase we were failing to prefer the copy assignment (which can take the result of the conversion operator directly) to a copy constructor followed by move assignment. The best way to fix this was to make the latter ill-formed, as it is supposed to be under DR 1138: just as you can't bind an rvalue reference to an lvalue variable, you can't bind it to the lvalue result of a conversion op either.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit ea7984932ac06b3899c0d7be78f7197f1c40421d
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jan 27 15:12:10 2014 -0500

    	PR c++/59823
    	Core DR 1138
    	* call.c (reference_binding): Pass LOOKUP_NO_TEMP_BIND for
    	list-initialization.  A conversion to rvalue ref that involves
    	an lvalue-rvalue conversion is bad.
    	(convert_like_real): Give helpful error message.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index b3db840..f6566cf 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1484,7 +1484,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
 	 direct-list-initialized, depending on the kind of initialization
 	 for the reference, and the reference is bound to that temporary. */
       conv = implicit_conversion (to, from, expr, c_cast_p,
-				  flags, complain);
+				  flags|LOOKUP_NO_TEMP_BIND, complain);
     skip:;
     }
 
@@ -1637,9 +1637,9 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
 
   /* [dcl.init.ref]
 
-     Otherwise, the reference shall be to a non-volatile const type.
-
-     Under C++0x, [8.5.3/5 dcl.init.ref] it may also be an rvalue reference */
+     Otherwise, the reference shall be an lvalue reference to a
+     non-volatile const type, or the reference shall be an rvalue
+     reference.  */
   if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
     return NULL;
 
@@ -1677,7 +1677,16 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
   /* This reference binding, unlike those above, requires the
      creation of a temporary.  */
   conv->need_temporary_p = true;
-  conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
+  if (TYPE_REF_IS_RVALUE (rto))
+    {
+      conv->rvaluedness_matches_p = 1;
+      /* In the second case, if the reference is an rvalue reference and
+	 the second standard conversion sequence of the user-defined
+	 conversion sequence includes an lvalue-to-rvalue conversion, the
+	 program is ill-formed.  */
+      if (conv->user_conv_p && next_conversion (conv)->kind == ck_rvalue)
+	conv->bad_p = 1;
+    }
 
   return conv;
 }
@@ -5881,7 +5890,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
       && convs->kind != ck_list
       && convs->kind != ck_ambig
       && (convs->kind != ck_ref_bind
-	  || convs->user_conv_p)
+	  || (convs->user_conv_p && next_conversion (convs)->bad_p))
       && (convs->kind != ck_rvalue
 	  || SCALAR_TYPE_P (totype))
       && convs->kind != ck_base)
@@ -6173,7 +6182,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	if (convs->bad_p && !next_conversion (convs)->bad_p)
 	  {
 	    gcc_assert (TYPE_REF_IS_RVALUE (ref_type)
-			&& real_lvalue_p (expr));
+			&& (real_lvalue_p (expr)
+			    || next_conversion(convs)->kind == ck_rvalue));
 
 	    error_at (loc, "cannot bind %qT lvalue to %qT",
 		      TREE_TYPE (expr), totype);
diff --git a/gcc/testsuite/g++.dg/cpp0x/overload3.C b/gcc/testsuite/g++.dg/cpp0x/overload3.C
new file mode 100644
index 0000000..e521b35
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/overload3.C
@@ -0,0 +1,17 @@
+// PR c++/59823
+// { dg-options "-std=c++11" }
+
+struct X { };
+
+void f(X&&);
+
+struct wrap
+{
+  operator const X&() const;
+};
+
+int main()
+{
+  wrap w;
+  f(w);				// { dg-error "lvalue" }
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]