diff options
author | Jason Merrill <jason@redhat.com> | 2014-05-09 14:16:18 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2014-05-09 14:16:18 -0400 |
commit | e8ee694a14382f4b2cea7ec5622e2be5329d581d (patch) | |
tree | a46b7e14b2418d4d41841748d0690d5f66ef478c /gcc | |
parent | bfa589517b23a771d285e1a0e7cb701b46c63d95 (diff) | |
download | gcc-e8ee694a14382f4b2cea7ec5622e2be5329d581d.zip gcc-e8ee694a14382f4b2cea7ec5622e2be5329d581d.tar.gz gcc-e8ee694a14382f4b2cea7ec5622e2be5329d581d.tar.bz2 |
DR 587 PR c++/51317
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/cp/call.c | 32 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/rv-cond2.C | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/expr/cond14.C | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/warn/return-reference.C | 2 |
5 files changed, 48 insertions, 8 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ab3a3f4..228fe95 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 187fc77..9e83c4a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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 index 0000000..e231b11 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/rv-cond2.C @@ -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 index 0000000..5276287 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/cond14.C @@ -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 diff --git a/gcc/testsuite/g++.dg/warn/return-reference.C b/gcc/testsuite/g++.dg/warn/return-reference.C index 8302190..710e87c 100644 --- a/gcc/testsuite/g++.dg/warn/return-reference.C +++ b/gcc/testsuite/g++.dg/warn/return-reference.C @@ -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& |