There were two problems with build_static_cast_1's handling of this
testcase:
1) We weren't using unlowered_expr_type to get the type of the
expression, so we were comparing int to the internal bit-field type,
which doesn't match.
2) We were trying to bind an lvalue reference to a bit-field in the
process of converting to rvalue reference, which doesn't work; for
bit-fields, we should convert to an rvalue temporary and then bind the
rvalue reference to that.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 1e5a058d0b7b0226a5956ee991b9a47757d2aedd
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Jan 16 13:12:26 2012 -0500
PR c++/51868
* typeck.c (build_static_cast_1): Handle bit-fields properly.
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 11edeee..91e7a0a 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/g++.dg/cpp0x/rv-bitfield.C b/gcc/testsuite/g++.dg/cpp0x/rv-bitfield.C
new file mode 100644
index 0000000..a269a76
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/rv-bitfield.C
@@ -0,0 +1,13 @@
+// { 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 0000000..e054151
--- /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();
+}