]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
DR 587 PR c++/51317
authorJason Merrill <jason@redhat.com>
Fri, 9 May 2014 18:16:18 +0000 (14:16 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 9 May 2014 18:16:18 +0000 (14:16 -0400)
DR 587
PR c++/51317
* call.c (build_conditional_expr_1, conditional_conversion): Handle
non-class lvalues and xvalues that differ only in cv-qualifiers.

From-SVN: r210285

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/g++.dg/cpp0x/rv-cond2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/expr/cond14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/return-reference.C

index ab3a3f4357d66d56f3e0829217f2a31ee2e9304e..228fe959822f2ccb12cc443e98082bc92799b78a 100644 (file)
@@ -1,5 +1,10 @@
 2014-05-09  Jason Merrill  <jason@redhat.com>
 
+       DR 587
+       PR c++/51317
+       * call.c (build_conditional_expr_1, conditional_conversion): Handle
+       non-class lvalues and xvalues that differ only in cv-qualifiers.
+
        DR 5
        PR c++/60019
        * call.c (build_user_type_conversion_1): The copy-init temporary
index 187fc776e46d869efea4f5b15f18c560dc4c90a5..9e83c4a8b73ae8b0cbe8f657e2901cb5cc6e911e 100644 (file)
@@ -4382,20 +4382,31 @@ conditional_conversion (tree e1, tree e2, tsubst_flags_t complain)
      If E2 is an lvalue: E1 can be converted to match E2 if E1 can be
      implicitly converted (clause _conv_) to the type "lvalue reference to
      T2", subject to the constraint that in the conversion the
-     reference must bind directly (_dcl.init.ref_) to an lvalue.  */
-  if (real_lvalue_p (e2))
+     reference must bind directly (_dcl.init.ref_) to an lvalue.
+
+     If E2 is an xvalue: E1 can be converted to match E2 if E1 can be
+     implicitly converted to the type "rvalue reference to T2", subject to
+     the constraint that the reference must bind directly.  */
+  if (lvalue_or_rvalue_with_address_p (e2))
     {
-      conv = implicit_conversion (build_reference_type (t2),
+      tree rtype = cp_build_reference_type (t2, !real_lvalue_p (e2));
+      conv = implicit_conversion (rtype,
                                  t1,
                                  e1,
                                  /*c_cast_p=*/false,
                                  LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND
                                  |LOOKUP_ONLYCONVERTING,
                                  complain);
-      if (conv)
+      if (conv && !conv->bad_p)
        return conv;
     }
 
+  /* If E2 is a prvalue or if neither of the conversions above can be done
+     and at least one of the operands has (possibly cv-qualified) class
+     type: */
+  if (!CLASS_TYPE_P (t1) && !CLASS_TYPE_P (t2))
+    return NULL;
+
   /* [expr.cond]
 
      If E1 and E2 have class type, and the underlying class types are
@@ -4690,10 +4701,17 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
   /* [expr.cond]
 
      Otherwise, if the second and third operand have different types,
-     and either has (possibly cv-qualified) class type, an attempt is
-     made to convert each of those operands to the type of the other.  */
+     and either has (possibly cv-qualified) class type, or if both are
+     glvalues of the same value category and the same type except for
+     cv-qualification, an attempt is made to convert each of those operands
+     to the type of the other.  */
   else if (!same_type_p (arg2_type, arg3_type)
-          && (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)))
+           && (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)
+               || (same_type_ignoring_top_level_qualifiers_p (arg2_type,
+                                                              arg3_type)
+                   && lvalue_or_rvalue_with_address_p (arg2)
+                   && lvalue_or_rvalue_with_address_p (arg3)
+                   && real_lvalue_p (arg2) == real_lvalue_p (arg3))))
     {
       conversion *conv2;
       conversion *conv3;
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-cond2.C b/gcc/testsuite/g++.dg/cpp0x/rv-cond2.C
new file mode 100644 (file)
index 0000000..e231b11
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++11 } }
+
+template <class T, class U> struct ST;
+template <class T> struct ST<T,T> {};
+
+int&& f();
+const int&& g();
+
+void h(bool b) {
+  ST<decltype(b ? f() : g()),const int&&>();
+}
diff --git a/gcc/testsuite/g++.dg/expr/cond14.C b/gcc/testsuite/g++.dg/expr/cond14.C
new file mode 100644 (file)
index 0000000..5276287
--- /dev/null
@@ -0,0 +1,6 @@
+// DR 587
+// PR c++/51317
+
+int x = 1;
+int const y = 2;
+int const *p = &(1 ? x : y); // error: lvalue required as unary '&' operand
index 83021900dbd7696d6b6737cae14979cb84791b83..710e87c8cbdfd2ba27c74f41d05f328898920fda 100644 (file)
@@ -7,7 +7,7 @@ foo1()
 {
   static int empty;
   const int* x = bar();
-  return (x ? *x : empty);      // { dg-bogus ".*" "" { xfail *-*-* } }
+  return (x ? *x : empty);      // { dg-bogus ".*" }
 }
 
 const int&