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

Reply via email to