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();
+}