DR 1571
authorJason Merrill <jason@redhat.com>
Tue, 25 Feb 2014 21:27:51 +0000 (16:27 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 25 Feb 2014 21:27:51 +0000 (16:27 -0500)
DR 1571
* call.c (reference_binding): Recurse on user-defined conversion.
(convert_like_real) [ck_ref_bind]: Explain cv-qual mismatch.

From-SVN: r208159

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/g++.dg/cpp0x/overload3.C
gcc/testsuite/g++.dg/cpp0x/rv-init1.C [new file with mode: 0644]

index b353499..a27643e 100644 (file)
@@ -1,5 +1,9 @@
 2014-02-25  Jason Merrill  <jason@redhat.com>
 
+       DR 1571
+       * call.c (reference_binding): Recurse on user-defined conversion.
+       (convert_like_real) [ck_ref_bind]: Explain cv-qual mismatch.
+
        * call.c (print_conversion_rejection): Handle n_arg of -2.
        (build_user_type_conversion_1): Pass it.
 
index 700099d..32767ec 100644 (file)
@@ -1677,20 +1677,37 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
   if (!conv)
     return NULL;
 
-  conv = build_conv (ck_ref_bind, rto, conv);
+  /* 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);
+
   /* This reference binding, unlike those above, requires the
      creation of a temporary.  */
   conv->need_temporary_p = true;
-  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;
-    }
+  conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
 
   return conv;
 }
@@ -6213,12 +6230,25 @@ 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)
-                           || next_conversion(convs)->kind == ck_rvalue));
-
-           error_at (loc, "cannot bind %qT lvalue to %qT",
-                     TREE_TYPE (expr), totype);
+           gcc_assert (TYPE_REF_IS_RVALUE (ref_type));
+
+           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;
+                 }
            if (fn)
              inform (input_location,
                      "initializing argument %P of %q+D", argnum, fn);
index e521b35..b8f781a 100644 (file)
@@ -13,5 +13,5 @@ struct wrap
 int main()
 {
   wrap w;
-  f(w);                                // { dg-error "lvalue" }
+  f(w);                                // { dg-error "" }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-init1.C b/gcc/testsuite/g++.dg/cpp0x/rv-init1.C
new file mode 100644 (file)
index 0000000..2e8d4f7
--- /dev/null
@@ -0,0 +1,26 @@
+// 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 "" }