diff --git a/bindgen-integration/cpp/Test.cc b/bindgen-integration/cpp/Test.cc index 80ae0239e5..e35216996c 100644 --- a/bindgen-integration/cpp/Test.cc +++ b/bindgen-integration/cpp/Test.cc @@ -1,5 +1,7 @@ #include "Test.h" +#include + const int Test::COUNTDOWN[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; const int* Test::COUNTDOWN_PTR = Test::COUNTDOWN; @@ -130,4 +132,17 @@ Seventh::assert(bool first, this->seventh_thirty_bits == seventh; }; +bool +Eight::assert(char a, unsigned b) const +{ + printf("{ a: %u, b: %u }\n", this->a, this->b); + return this->a == a && this->b == b; +} + +bool +Ninth::assert(char a, unsigned short b) const +{ + return this->a == a && this->b == b; +} + } // namespace bitfields diff --git a/bindgen-integration/cpp/Test.h b/bindgen-integration/cpp/Test.h index e09c9ee72a..1e8b69db94 100644 --- a/bindgen-integration/cpp/Test.h +++ b/bindgen-integration/cpp/Test.h @@ -163,6 +163,22 @@ struct Seventh { int seventh); }; +struct Eight { + unsigned char a; + unsigned b : 15; + + /// Returns true if the bitfields match the arguments, false otherwise. + bool assert(char a, unsigned b) const; +}; + +struct Ninth { + unsigned char a; + unsigned short b : 15; + + /// Returns true if the bitfields match the arguments, false otherwise. + bool assert(char a, unsigned short b) const; +}; + } // namespace bitfields struct AutoRestoreBool { diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index 74b4df4f42..0bb22f85d6 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -213,6 +213,34 @@ fn test_bitfields_seventh() { assert_eq!(large.seventh_thirty_bits(), 1061657575); } +#[test] +fn test_bitfields_eight() { + let mut s: bindings::bitfields::Eight = unsafe { mem::zeroed() }; + assert!(unsafe { s.assert(0, 0) }); + + s.a = 10; + s.set_b(1); + + assert!(unsafe { s.assert(10, 1) }); + + assert_eq!(s.a, 10); + assert_eq!(s.b(), 1); +} + +#[test] +fn test_bitfields_ninth() { + let mut s: bindings::bitfields::Ninth = unsafe { mem::zeroed() }; + assert!(unsafe { s.assert(0, 0) }); + + s.a = 10; + s.set_b(656); + + assert!(unsafe { s.assert(10, 656) }); + + assert_eq!(s.a, 10); + assert_eq!(s.b(), 656); +} + #[test] fn test_bitfield_constructors() { use std::mem; diff --git a/src/ir/comp.rs b/src/ir/comp.rs index 8c52906728..dc52c33678 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -604,6 +604,7 @@ where let bitfield_size = bitfield_layout.size; let bitfield_align = bitfield_layout.align; + debug!("{:?}, {:?}", bitfield, bitfield_layout); let mut offset = unit_size_in_bits; if is_ms_struct { if unit_size_in_bits != 0 && @@ -627,10 +628,9 @@ where unit_align = 0; } } else { - if offset != 0 && - (bitfield_width == 0 || + if bitfield_width == 0 || (offset & (bitfield_align * 8 - 1)) + bitfield_width > - bitfield_size * 8) + bitfield_size * 8 { offset = align_to(offset, bitfield_align * 8); } diff --git a/tests/expectations/tests/issue-1314-bitfield-align.rs b/tests/expectations/tests/issue-1314-bitfield-align.rs new file mode 100644 index 0000000000..066d845eb3 --- /dev/null +++ b/tests/expectations/tests/issue-1314-bitfield-align.rs @@ -0,0 +1,179 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + storage: Storage, + align: [Align; 0], +} + +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + pub fn new(storage: Storage) -> Self { + Self { storage, align: [] } + } + + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + + let bit_index = index % 8; + let mask = 1 << bit_index; + + byte & mask == mask + } + + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + + let bit_index = index % 8; + let mask = 1 << bit_index; + + if val { + *byte |= mask; + } else { + *byte &= !mask; + } + } + + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + + let mut val = 0; + + for i in 0..(bit_width as usize) { + if self.get_bit(i + bit_offset) { + val |= 1 << i; + } + } + + val + } + + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + self.set_bit(i + bit_offset, val_bit_is_set); + } + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct S { + pub a: u8, + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize], u16>, + pub __bindgen_align: [u32; 0usize], +} +#[test] +fn bindgen_test_layout_S() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(S)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(S)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).a as *const _ as usize }, + 0usize, + concat!("Offset of field: ", stringify!(S), "::", stringify!(a)) + ); +} +impl S { + #[inline] + pub fn b(&self) -> u32 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 15u8) as u32) } + } + #[inline] + pub fn set_b(&mut self, val: u32) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 15u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1(b: u32) -> __BindgenBitfieldUnit<[u8; 2usize], u16> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize], u16> = + Default::default(); + __bindgen_bitfield_unit.set(0usize, 15u8, { + let b: u32 = unsafe { ::std::mem::transmute(b) }; + b as u64 + }); + __bindgen_bitfield_unit + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct S2 { + pub a: u8, + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize], u16>, + pub __bindgen_align: [u16; 0usize], +} +#[test] +fn bindgen_test_layout_S2() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(S2)) + ); + assert_eq!( + ::std::mem::align_of::(), + 2usize, + concat!("Alignment of ", stringify!(S2)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).a as *const _ as usize }, + 0usize, + concat!("Offset of field: ", stringify!(S2), "::", stringify!(a)) + ); +} +impl S2 { + #[inline] + pub fn b(&self) -> u16 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 15u8) as u16) } + } + #[inline] + pub fn set_b(&mut self, val: u16) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 15u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1(b: u16) -> __BindgenBitfieldUnit<[u8; 2usize], u16> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize], u16> = + Default::default(); + __bindgen_bitfield_unit.set(0usize, 15u8, { + let b: u16 = unsafe { ::std::mem::transmute(b) }; + b as u64 + }); + __bindgen_bitfield_unit + } +} diff --git a/tests/headers/issue-1314-bitfield-align.h b/tests/headers/issue-1314-bitfield-align.h new file mode 100644 index 0000000000..0bbfb61020 --- /dev/null +++ b/tests/headers/issue-1314-bitfield-align.h @@ -0,0 +1,13 @@ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned uint32_t; + +typedef struct { + uint8_t a; + uint32_t b : 15; +} S; + +typedef struct { + uint8_t a; + uint16_t b : 15; +} S2;