diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 86ab82f985a034eda8827c5dd1326952e825cf0c..a5a07e47db8357f22166b7202c312706feb461c7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2012-01-16 Jason Merrill <jason@redhat.com> + + PR c++/51868 + * typeck.c (build_static_cast_1): Handle bit-fields properly. + 2012-01-13 Ian Lance Taylor <iant@google.com> PR c++/50012 diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 11edeeed3b91c0606585f2e40529f703923fc05c..91e7a0a09ca7e9de904fdd2b20a1b1a5feaff56a 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5812,11 +5812,12 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p, { tree intype; tree result; + cp_lvalue_kind clk; /* Assume the cast is valid. */ *valid_p = true; - intype = TREE_TYPE (expr); + intype = unlowered_expr_type (expr); /* Save casted types in the function's used types hash table. */ used_types_insert (type); @@ -5882,22 +5883,29 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p, cv2 T2 if cv2 T2 is reference-compatible with cv1 T1 (8.5.3)." */ if (TREE_CODE (type) == REFERENCE_TYPE && TYPE_REF_IS_RVALUE (type) - && real_lvalue_p (expr) + && (clk = real_lvalue_p (expr)) && reference_related_p (TREE_TYPE (type), intype) && (c_cast_p || at_least_as_qualified_p (TREE_TYPE (type), intype))) { - /* Handle the lvalue case here by casting to lvalue reference and - then changing it to an rvalue reference. Casting an xvalue to - rvalue reference will be handled by the main code path. */ - tree lref = cp_build_reference_type (TREE_TYPE (type), false); - result = (perform_direct_initialization_if_possible - (lref, expr, c_cast_p, complain)); - result = cp_fold_convert (type, result); - /* Make sure we don't fold back down to a named rvalue reference, - because that would be an lvalue. */ - if (DECL_P (result)) - result = build1 (NON_LVALUE_EXPR, type, result); - return convert_from_reference (result); + if (clk == clk_ordinary) + { + /* Handle the (non-bit-field) lvalue case here by casting to + lvalue reference and then changing it to an rvalue reference. + Casting an xvalue to rvalue reference will be handled by the + main code path. */ + tree lref = cp_build_reference_type (TREE_TYPE (type), false); + result = (perform_direct_initialization_if_possible + (lref, expr, c_cast_p, complain)); + result = cp_fold_convert (type, result); + /* Make sure we don't fold back down to a named rvalue reference, + because that would be an lvalue. */ + if (DECL_P (result)) + result = build1 (NON_LVALUE_EXPR, type, result); + return convert_from_reference (result); + } + else + /* For a bit-field or packed field, bind to a temporary. */ + expr = rvalue (expr); } /* Resolve overloaded address here rather than once in diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4e58ca5c01865431a53a2ee957c8b0c56c978c3b..0bdffcc3761b7e7c6f0c945a1afc1d717f8f3c17 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2012-01-16 Jason Merrill <jason@redhat.com> + + PR c++/51868 + * g++.dg/cpp0x/rv-bitfield.C: New. + * g++.dg/cpp0x/rv-bitfield2.C: New. + 2012-01-16 Paul Thomas <pault@gcc.gnu.org> * gfortran.dg/class_array_3.f03: Remove the explicit loop in diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-bitfield.C b/gcc/testsuite/g++.dg/cpp0x/rv-bitfield.C new file mode 100644 index 0000000000000000000000000000000000000000..ed866f9e1f37f595cdb7beb15dc86153c8ee0947 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/rv-bitfield.C @@ -0,0 +1,12 @@ +// { dg-options -std=c++0x } + +struct A +{ + int i : 1; +}; + +int main() +{ + A a; + static_cast<int&&>(a.i); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-bitfield2.C b/gcc/testsuite/g++.dg/cpp0x/rv-bitfield2.C new file mode 100644 index 0000000000000000000000000000000000000000..e054151b056bd96c12d7d05be48f2e153ede048f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/rv-bitfield2.C @@ -0,0 +1,17 @@ +// PR c++/51868 +// { dg-options -std=c++0x } + +struct A { + A() {} + A(const A&) {} + A(A&&) {} +}; + +struct B { + A a; + int f : 1; +}; + +B func() { + return B(); +}