From 2f75f5154f05bd9ebc4e582ec5b4aca9f1d8bbac Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Wed, 26 Feb 2014 11:48:22 -0500
Subject: [PATCH] re PR c++/60345 (r208159 causes Firefox build error)

	PR c++/60345
	Revert:
	DR 1571
	* call.c (reference_binding): Recurse on user-defined conversion.
	(convert_like_real) [ck_ref_bind]: Explain cv-qual mismatch.

From-SVN: r208175
---
 gcc/cp/ChangeLog                       |  8 ++++
 gcc/cp/call.c                          | 62 +++++++-------------------
 gcc/testsuite/g++.dg/cpp0x/overload3.C |  2 +-
 gcc/testsuite/g++.dg/cpp0x/rv-init1.C  | 26 -----------
 4 files changed, 25 insertions(+), 73 deletions(-)
 delete mode 100644 gcc/testsuite/g++.dg/cpp0x/rv-init1.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a27643eef91e..ce6085d736fb 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2014-02-26  Jason Merrill  <jason@redhat.com>
+
+	PR c++/60345
+	Revert:
+	DR 1571
+	* call.c (reference_binding): Recurse on user-defined conversion.
+	(convert_like_real) [ck_ref_bind]: Explain cv-qual mismatch.
+
 2014-02-25  Jason Merrill  <jason@redhat.com>
 
 	DR 1571
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 32767ec7c062..700099d99ddf 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1677,37 +1677,20 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
   if (!conv)
     return NULL;
 
-  /* Limit this to C++11 mode for GCC 4.9, to be safe.  */
-  if (cxx_dialect >= cxx11 && conv->user_conv_p)
-    {
-      /* If initializing the temporary used a conversion function,
-	 recalculate the second conversion sequence.  */
-      for (conversion *t = conv; t; t = next_conversion (t))
-	if (t->kind == ck_user
-	    && DECL_CONV_FN_P (t->cand->fn))
-	  {
-	    tree ftype = TREE_TYPE (TREE_TYPE (t->cand->fn));
-	    if (TREE_CODE (ftype) != REFERENCE_TYPE)
-	      /* Pretend we start from an xvalue to avoid trouble from
-		 LOOKUP_NO_TEMP_BIND.  */
-	      ftype = cp_build_reference_type (ftype, true);
-	    conversion *new_second
-	      = reference_binding (rto, ftype, NULL_TREE, c_cast_p,
-				   flags|LOOKUP_NO_CONVERSION, complain);
-	    if (!new_second)
-	      return NULL;
-	    conv = merge_conversion_sequences (t, new_second);
-	    break;
-	  }
-    }
-
-  if (conv->kind != ck_ref_bind)
-    conv = build_conv (ck_ref_bind, rto, conv);
-
+  conv = build_conv (ck_ref_bind, rto, conv);
   /* 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;
 }
@@ -6230,25 +6213,12 @@ 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));
+	    gcc_assert (TYPE_REF_IS_RVALUE (ref_type)
+			&& (real_lvalue_p (expr)
+			    || next_conversion(convs)->kind == ck_rvalue));
 
-	    if (real_lvalue_p (expr)
-		|| next_conversion(convs)->kind == ck_rvalue)
-	      error_at (loc, "cannot bind %qT lvalue to %qT",
-			TREE_TYPE (expr), totype);
-	    else if (!reference_compatible_p (totype, TREE_TYPE (expr)))
-	      error_at (loc, "binding %qT to reference of type %qT "
-			"discards qualifiers", TREE_TYPE (expr),totype);
-	    else
-	      gcc_unreachable ();
-	    if (convs->user_conv_p)
-	      for (conversion *t = convs; t; t = next_conversion (t))
-		if (t->kind == ck_user)
-		  {
-		    print_z_candidate (loc, "after user-defined conversion:",
-				       t->cand);
-		    break;
-		  }
+	    error_at (loc, "cannot bind %qT lvalue to %qT",
+		      TREE_TYPE (expr), totype);
 	    if (fn)
 	      inform (input_location,
 		      "initializing argument %P of %q+D", argnum, fn);
diff --git a/gcc/testsuite/g++.dg/cpp0x/overload3.C b/gcc/testsuite/g++.dg/cpp0x/overload3.C
index b8f781ad3f7f..e521b35bd0db 100644
--- a/gcc/testsuite/g++.dg/cpp0x/overload3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/overload3.C
@@ -13,5 +13,5 @@ struct wrap
 int main()
 {
   wrap w;
-  f(w);				// { dg-error "" }
+  f(w);				// { dg-error "lvalue" }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-init1.C b/gcc/testsuite/g++.dg/cpp0x/rv-init1.C
deleted file mode 100644
index 2e8d4f748efe..000000000000
--- a/gcc/testsuite/g++.dg/cpp0x/rv-init1.C
+++ /dev/null
@@ -1,26 +0,0 @@
-// Core DR 1604/1571/1572
-// { dg-require-effective-target c++11 }
-
-struct Banana { };
-struct Enigma { operator const Banana(); };
-struct Doof { operator Banana&(); };
-void enigmatic() {
-  typedef const Banana ConstBanana;
-  Banana &&banana1 = ConstBanana(); // { dg-error "" }
-  Banana &&banana2 = Enigma();      // { dg-error "" }
-  Banana &&banana3 = Doof();        // { dg-error "" }
-}
-
-class A {
-public:
-  operator volatile int &();
-};
-A a;
-
-const int & ir1a = a.operator volatile int&(); // { dg-error "" }
-const int & ir2a = a;			       // { dg-error "" }
-
-struct X {
-  operator int&();
-} x;
-int&& rri2 = X();		// { dg-error "" }