base: Fix bitstruct bug with assigning fields

Given a BitStruct 'foo', where bar was a BitStructField, assignment was
broken because it was using the C++ default behavior (copy the entire
word).

  foo.bar = other_foo.bar

This will now correctly use BitFieldInsert to update the 'bar' bitfield.

Change-Id: I1464462ffd4df22ad14a2e43a34f74d75ac2809a
diff --git a/runtime/base/bit_struct.h b/runtime/base/bit_struct.h
index 1f86ee1..16b555e 100644
--- a/runtime/base/bit_struct.h
+++ b/runtime/base/bit_struct.h
@@ -130,6 +130,18 @@
     return kBitWidth;
   }
 
+  BitStructField& operator=(const BitStructField& other) {
+    // Warning. The default operator= will overwrite the entire storage!
+    return *this = static_cast<T>(other);
+  }
+
+  BitStructField(const BitStructField& other) {
+    Assign(*this, static_cast<T>(other));
+  }
+
+  BitStructField() = default;
+  ~BitStructField() = default;
+
  protected:
   template <typename T2>
   T2& Assign(T2& what, T value) {
@@ -265,7 +277,11 @@
 #define BITSTRUCT_DEFINE_START(name, bitwidth)                                 \
     union name {                                                               \
       art::detail::DefineBitStructSize<(bitwidth)> _;                          \
-      static constexpr size_t BitStructSizeOf() { return (bitwidth); }
+      static constexpr size_t BitStructSizeOf() { return (bitwidth); }         \
+      name& operator=(const name& other) { _ = other._; return *this; }        \
+      name(const name& other) : _(other._) {}                                  \
+      name() = default;                                                        \
+      ~name() = default;
 
 // End the definition of a bitstruct, and insert a sanity check
 // to ensure that the bitstruct did not exceed the specified size.
diff --git a/runtime/base/bit_struct_test.cc b/runtime/base/bit_struct_test.cc
index 9fc9762..a80d39e 100644
--- a/runtime/base/bit_struct_test.cc
+++ b/runtime/base/bit_struct_test.cc
@@ -255,4 +255,68 @@
   EXPECT_EQ(0b10101010101010101011111010100111u, AsUint(tst));
 }
 
+BITSTRUCT_DEFINE_START(TestBitStruct_u8, /* size */ 8)
+  BitStructInt</*lsb*/0, /*width*/3> i3;
+  BitStructUint</*lsb*/3, /*width*/4> u4;
+
+  BitStructUint</*lsb*/0, /*width*/8> alias_all;
+BITSTRUCT_DEFINE_END(TestBitStruct_u8);
+
+TEST(BitStructs, FieldAssignment) {
+  TestBitStruct_u8 all_1s{};  // NOLINT
+  all_1s.alias_all = 0xffu;
+
+  {
+    TestBitStruct_u8 tst{};  // NOLINT
+    tst.i3 = all_1s.i3;
+
+    // Copying a single bitfield does not copy all bitfields.
+    EXPECT_EQ(0b111, tst.alias_all);
+  }
+
+  {
+    TestBitStruct_u8 tst{};  // NOLINT
+    tst.u4 = all_1s.u4;
+
+    // Copying a single bitfield does not copy all bitfields.
+    EXPECT_EQ(0b1111000, tst.alias_all);
+  }
+}
+
+BITSTRUCT_DEFINE_START(NestedStruct, /* size */ 64)
+  BitStructField<MixedSizeBitStruct, /*lsb*/0> mixed_lower;
+  BitStructField<MixedSizeBitStruct, /*lsb*/32> mixed_upper;
+
+  BitStructUint</*lsb*/0, /*width*/64> alias_all;
+BITSTRUCT_DEFINE_END(NestedStruct);
+
+TEST(BitStructs, NestedFieldAssignment) {
+  MixedSizeBitStruct mixed_all_1s{};  // NOLINT
+  mixed_all_1s.alias_all = 0xFFFFFFFFu;
+
+  {
+    NestedStruct xyz{};  // NOLINT
+
+    NestedStruct other{};  // NOLINT
+    other.mixed_upper = mixed_all_1s;
+    other.mixed_lower = mixed_all_1s;
+
+    // Copying a single bitfield does not copy all bitfields.
+    xyz.mixed_lower = other.mixed_lower;
+    EXPECT_EQ(0xFFFFFFFFu, xyz.alias_all);
+  }
+
+  {
+    NestedStruct xyz{};  // NOLINT
+
+    NestedStruct other{};  // NOLINT
+    other.mixed_upper = mixed_all_1s;
+    other.mixed_lower = mixed_all_1s;
+
+    // Copying a single bitfield does not copy all bitfields.
+    xyz.mixed_upper = other.mixed_upper;
+    EXPECT_EQ(0xFFFFFFFF00000000u, xyz.alias_all);
+  }
+}
+
 }  // namespace art