commit 500305e38a79e4977bdfbda12d79c5401a149e9c
Author: Jason Merrill <jason@redhat.com>
Date: Fri May 9 00:00:32 2014 -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.
@@ -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;
new file mode 100644
@@ -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&&>();
+}
new file mode 100644
@@ -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
@@ -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&