From 11be5117ec89aa0195c68490a7582d1a7be1573a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 11 Jul 2025 22:45:07 +0200 Subject: [PATCH] comp: Fix alignment of bitfields in some edge cases. In order to properly compute the size of the bitfield for overaligned fields, we need to know the offset in the struct, not just in the allocation unit. E.g., something like: char; // Byte 1 char: 8; // Byte 2 short: 16; // Bytes 3 and 4 Should align differently than: char: 8; // Byte 1 short: 16; // Bytes 3 and 4 If we can't find the start offset in the struct, we fall back to our previous behavior (this can happen with C++ templates for example). We remove some code related to `is_ms_struct`, which was effectively dead. If someone cares about it they can resurrect it. We also don't align per-bitfield unit, but in order to mostly preserve behavior, we keep inserting a field at the beginning of the struct rather than using repr(align). Otherwise we hit #2179 in cases where we did not use to. We might want to extend that approach to repr(align) stuff, in order to try to fix #2179 more often, but for now do the minimal change. Fixes #1377 Fixes #3105 Fixes #743 Fixes #981 Fixes #1314 Co-authored-by: qinghon --- bindgen-integration/src/lib.rs | 5 +- .../tests/bitfield-32bit-overflow.rs | 1 - .../expectations/tests/bitfield-large.rs | 2 - .../expectations/tests/bitfield-linux-32.rs | 9 +- .../tests/bitfield-method-same-name.rs | 1 - .../expectations/tests/bitfield-template.rs | 214 ++++++++ .../expectations/tests/bitfield_align.rs | 15 +- .../expectations/tests/bitfield_align_2.rs | 2 +- .../tests/bitfield_large_overflow.rs | 2 +- .../tests/bitfield_method_mangling.rs | 2 +- .../tests/bitfield_pack_offset.rs | 507 ++++++++++++++++++ .../tests/bitfield_pragma_packed.rs | 3 +- .../tests/blocklist_bitfield_unit.rs | 1 - .../tests/default_visibility_crate.rs | 1 - .../tests/default_visibility_private.rs | 1 - ...bility_private_respects_cxx_access_spec.rs | 1 - .../tests/derive-bitfield-method-same-name.rs | 1 - .../tests/derive-debug-bitfield-1-51.rs | 1 - .../tests/derive-debug-bitfield-core.rs | 1 - .../tests/derive-debug-bitfield.rs | 1 - .../tests/derive-partialeq-bitfield.rs | 1 - .../tests/divide-by-zero-in-struct-layout.rs | 3 - .../tests/field-visibility-callback.rs | 1 - .../expectations/tests/field-visibility.rs | 6 +- .../tests/incomplete-array-padding.rs | 1 - .../tests/expectations/tests/issue-1034.rs | 1 - .../issue-1076-unnamed-bitfield-alignment.rs | 1 - .../tests/expectations/tests/issue-1947.rs | 3 +- .../tests/issue-739-pointer-wide-bitfield.rs | 2 +- .../tests/expectations/tests/issue-743.rs | 225 ++++++++ .../tests/expectations/tests/issue-816.rs | 3 +- .../expectations/tests/jsval_layout_opaque.rs | 2 +- .../tests/expectations/tests/layout_align.rs | 3 +- .../expectations/tests/layout_eth_conf.rs | 2 - .../tests/expectations/tests/layout_mbuf.rs | 7 +- .../expectations/tests/only_bitfields.rs | 1 - .../expectations/tests/packed-bitfield.rs | 1 - .../expectations/tests/private_fields.rs | 10 +- .../tests/redundant-packed-and-align.rs | 3 +- .../tests/struct_with_bitfields.rs | 2 - .../tests/expectations/tests/timex.rs | 2 - .../expectations/tests/union_bitfield.rs | 30 +- .../tests/union_with_anon_struct_bitfield.rs | 2 +- .../expectations/tests/weird_bitfields.rs | 2 - .../tests/headers/bitfield-linux-32.hpp | 2 +- .../tests/headers/bitfield-template.hpp | 4 + .../tests/headers/bitfield_pack_offset.h | 21 + bindgen-tests/tests/headers/issue-743.h | 6 + bindgen-tests/tests/headers/union_bitfield.h | 6 +- bindgen/codegen/mod.rs | 38 +- bindgen/codegen/struct_layout.rs | 31 -- bindgen/ir/comp.rs | 103 ++-- 52 files changed, 1074 insertions(+), 222 deletions(-) create mode 100644 bindgen-tests/tests/expectations/tests/bitfield-template.rs create mode 100644 bindgen-tests/tests/expectations/tests/bitfield_pack_offset.rs create mode 100644 bindgen-tests/tests/expectations/tests/issue-743.rs create mode 100644 bindgen-tests/tests/headers/bitfield-template.hpp create mode 100644 bindgen-tests/tests/headers/bitfield_pack_offset.h create mode 100644 bindgen-tests/tests/headers/issue-743.h diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index 64f4926a8b..c5362bf450 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -178,19 +178,18 @@ fn test_bitfields_seventh() { fn test_bitfield_constructors() { use std::mem; let mut first = bindings::bitfields::First { - _bitfield_align_1: [], _bitfield_1: bindings::bitfields::First::new_bitfield_1(1, 2, 3), }; assert!(unsafe { first.assert(1, 2, 3) }); let mut second = bindings::bitfields::Second { - _bitfield_align_1: [], + _bindgen_align: [], _bitfield_1: bindings::bitfields::Second::new_bitfield_1(1337, true), }; assert!(unsafe { second.assert(1337, true) }); let mut third = bindings::bitfields::Third { - _bitfield_align_1: [], + _bindgen_align: [], _bitfield_1: bindings::bitfields::Third::new_bitfield_1( 42, false, diff --git a/bindgen-tests/tests/expectations/tests/bitfield-32bit-overflow.rs b/bindgen-tests/tests/expectations/tests/bitfield-32bit-overflow.rs index 81ce12a5c9..783f0ef7a9 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield-32bit-overflow.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield-32bit-overflow.rs @@ -148,7 +148,6 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct MuchBitfield { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 5usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/bitfield-large.rs b/bindgen-tests/tests/expectations/tests/bitfield-large.rs index 8024d88c3b..5d614ab936 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield-large.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield-large.rs @@ -149,7 +149,6 @@ where #[repr(align(16))] #[derive(Debug, Default, Copy, Clone)] pub struct HasBigBitfield { - pub _bitfield_align_1: [u64; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 16usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -213,7 +212,6 @@ impl HasBigBitfield { #[repr(align(16))] #[derive(Debug, Default, Copy, Clone)] pub struct HasTwoBigBitfields { - pub _bitfield_align_1: [u64; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 16usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/bitfield-linux-32.rs b/bindgen-tests/tests/expectations/tests/bitfield-linux-32.rs index 8b0b37b481..3e676c53b5 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield-linux-32.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield-linux-32.rs @@ -145,19 +145,12 @@ where } } } -#[repr(C, packed(4))] +#[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Test { pub foo: u64, - pub _bitfield_align_1: [u64; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>, } -#[allow(clippy::unnecessary_operation, clippy::identity_op)] -const _: () = { - ["Size of Test"][::std::mem::size_of::() - 16usize]; - ["Alignment of Test"][::std::mem::align_of::() - 4usize]; - ["Offset of field: Test::foo"][::std::mem::offset_of!(Test, foo) - 0usize]; -}; impl Test { #[inline] pub fn x(&self) -> u64 { diff --git a/bindgen-tests/tests/expectations/tests/bitfield-method-same-name.rs b/bindgen-tests/tests/expectations/tests/bitfield-method-same-name.rs index 84e152f3fd..09ca005589 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield-method-same-name.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield-method-same-name.rs @@ -148,7 +148,6 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Foo { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/bitfield-template.rs b/bindgen-tests/tests/expectations/tests/bitfield-template.rs new file mode 100644 index 0000000000..eb454e0db4 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/bitfield-template.rs @@ -0,0 +1,214 @@ +#![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 { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + fn extract_bit(byte: u8, index: usize) -> bool { + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[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]; + Self::extract_bit(byte, index) + } + #[inline] + pub unsafe fn raw_get_bit(this: *const Self, index: usize) -> bool { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = unsafe { + *(core::ptr::addr_of!((*this).storage) as *const u8) + .offset(byte_index as isize) + }; + Self::extract_bit(byte, index) + } + #[inline] + fn change_bit(byte: u8, index: usize, val: bool) -> u8 { + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { byte | mask } else { byte & !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]; + *byte = Self::change_bit(*byte, index, val); + } + #[inline] + pub unsafe fn raw_set_bit(this: *mut Self, index: usize, val: bool) { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = unsafe { + (core::ptr::addr_of_mut!((*this).storage) as *mut u8) + .offset(byte_index as isize) + }; + unsafe { *byte = Self::change_bit(*byte, index, val) }; + } + #[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) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub unsafe fn raw_get(this: *const Self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::(), + ); + let mut val = 0; + for i in 0..(bit_width as usize) { + if unsafe { Self::raw_get_bit(this, i + bit_offset) } { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + 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; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } + #[inline] + pub unsafe fn raw_set(this: *mut Self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::(), + ); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + unsafe { Self::raw_set_bit(this, index + bit_offset, val_bit_is_set) }; + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct foo { + pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + pub member: T, + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, +} +impl Default for foo { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl foo { + #[inline] + pub fn b(&self) -> bool { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 8u8) as u8) } + } + #[inline] + pub fn set_b(&mut self, val: bool) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 8u8, val as u64) + } + } + #[inline] + pub unsafe fn b_raw(this: *const Self) -> bool { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 0usize, 8u8) as u8, + ) + } + } + #[inline] + pub unsafe fn set_b_raw(this: *mut Self, val: bool) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 0usize, + 8u8, + val as u64, + ) + } + } + #[inline] + pub fn new_bitfield_1(b: bool) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default(); + __bindgen_bitfield_unit + .set( + 0usize, + 8u8, + { + let b: u8 = unsafe { ::std::mem::transmute(b) }; + b as u64 + }, + ); + __bindgen_bitfield_unit + } +} diff --git a/bindgen-tests/tests/expectations/tests/bitfield_align.rs b/bindgen-tests/tests/expectations/tests/bitfield_align.rs index 5f1321bbb1..0c70917fc5 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield_align.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield_align.rs @@ -146,11 +146,10 @@ where } } #[repr(C)] -#[repr(align(4))] #[derive(Debug, Default, Copy, Clone)] pub struct A { + pub _bindgen_align: [u32; 0], pub x: ::std::os::raw::c_uchar, - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>, pub y: ::std::os::raw::c_uchar, } @@ -632,7 +631,7 @@ impl A { #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct B { - pub _bitfield_align_1: [u32; 0], + pub _bindgen_align: [u32; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -744,7 +743,6 @@ impl B { #[derive(Debug, Default, Copy, Clone)] pub struct C { pub x: ::std::os::raw::c_uchar, - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub baz: ::std::os::raw::c_uint, } @@ -856,10 +854,9 @@ impl C { } } #[repr(C)] -#[repr(align(2))] #[derive(Debug, Default, Copy, Clone)] pub struct Date1 { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u16; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 3usize]>, pub __bindgen_padding_0: u8, } @@ -1061,10 +1058,9 @@ impl Date1 { } } #[repr(C)] -#[repr(align(2))] #[derive(Debug, Default, Copy, Clone)] pub struct Date2 { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u16; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -1311,10 +1307,9 @@ impl Date2 { } } #[repr(C)] -#[repr(align(2))] #[derive(Debug, Default, Copy, Clone)] pub struct Date3 { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u16; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 3usize]>, pub byte: ::std::os::raw::c_uchar, } diff --git a/bindgen-tests/tests/expectations/tests/bitfield_align_2.rs b/bindgen-tests/tests/expectations/tests/bitfield_align_2.rs index 2a676d5636..b71bba18ad 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield_align_2.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield_align_2.rs @@ -157,7 +157,7 @@ pub enum MyEnum { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct TaggedPtr { - pub _bitfield_align_1: [u64; 0], + pub _bindgen_align: [u64; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/bitfield_large_overflow.rs b/bindgen-tests/tests/expectations/tests/bitfield_large_overflow.rs index 51c777497b..ed7d1b3bb7 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield_large_overflow.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield_large_overflow.rs @@ -1,8 +1,8 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] #[repr(C)] -#[repr(align(8))] #[derive(Debug, Default, Copy, Clone)] pub struct _bindgen_ty_1 { + pub _bindgen_align: [u64; 0], pub _bindgen_opaque_blob: [u64; 10usize], } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/bitfield_method_mangling.rs b/bindgen-tests/tests/expectations/tests/bitfield_method_mangling.rs index 1a08cd00f9..35117c74b6 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield_method_mangling.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield_method_mangling.rs @@ -148,7 +148,7 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct mach_msg_type_descriptor_t { - pub _bitfield_align_1: [u32; 0], + pub _bindgen_align: [u32; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/bitfield_pack_offset.rs b/bindgen-tests/tests/expectations/tests/bitfield_pack_offset.rs new file mode 100644 index 0000000000..d654e25b27 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/bitfield_pack_offset.rs @@ -0,0 +1,507 @@ +#![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 { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + fn extract_bit(byte: u8, index: usize) -> bool { + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[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]; + Self::extract_bit(byte, index) + } + #[inline] + pub unsafe fn raw_get_bit(this: *const Self, index: usize) -> bool { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = unsafe { + *(core::ptr::addr_of!((*this).storage) as *const u8) + .offset(byte_index as isize) + }; + Self::extract_bit(byte, index) + } + #[inline] + fn change_bit(byte: u8, index: usize, val: bool) -> u8 { + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { byte | mask } else { byte & !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]; + *byte = Self::change_bit(*byte, index, val); + } + #[inline] + pub unsafe fn raw_set_bit(this: *mut Self, index: usize, val: bool) { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = unsafe { + (core::ptr::addr_of_mut!((*this).storage) as *mut u8) + .offset(byte_index as isize) + }; + unsafe { *byte = Self::change_bit(*byte, index, val) }; + } + #[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) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub unsafe fn raw_get(this: *const Self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::(), + ); + let mut val = 0; + for i in 0..(bit_width as usize) { + if unsafe { Self::raw_get_bit(this, i + bit_offset) } { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + 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; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } + #[inline] + pub unsafe fn raw_set(this: *mut Self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::(), + ); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + unsafe { Self::raw_set_bit(this, index + bit_offset, val_bit_is_set) }; + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct A { + pub name: [::std::os::raw::c_uchar; 7usize], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 3usize]>, + pub maxYield: ::std::os::raw::c_uchar, + pub _bitfield_2: __BindgenBitfieldUnit<[u8; 1usize]>, + pub description1: *const ::std::os::raw::c_uchar, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of A"][::std::mem::size_of::() - 24usize]; + ["Alignment of A"][::std::mem::align_of::() - 8usize]; + ["Offset of field: A::name"][::std::mem::offset_of!(A, name) - 0usize]; + ["Offset of field: A::maxYield"][::std::mem::offset_of!(A, maxYield) - 10usize]; + [ + "Offset of field: A::description1", + ][::std::mem::offset_of!(A, description1) - 16usize]; +}; +impl Default for A { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl A { + #[inline] + pub fn firmness(&self) -> ::std::os::raw::c_uchar { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 4u8) as u8) } + } + #[inline] + pub fn set_firmness(&mut self, val: ::std::os::raw::c_uchar) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 4u8, val as u64) + } + } + #[inline] + pub unsafe fn firmness_raw(this: *const Self) -> ::std::os::raw::c_uchar { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 0usize, 4u8) as u8, + ) + } + } + #[inline] + pub unsafe fn set_firmness_raw(this: *mut Self, val: ::std::os::raw::c_uchar) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 0usize, + 4u8, + val as u64, + ) + } + } + #[inline] + pub fn color(&self) -> ::std::os::raw::c_uchar { + unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 4u8) as u8) } + } + #[inline] + pub fn set_color(&mut self, val: ::std::os::raw::c_uchar) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(4usize, 4u8, val as u64) + } + } + #[inline] + pub unsafe fn color_raw(this: *const Self) -> ::std::os::raw::c_uchar { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 4usize, 4u8) as u8, + ) + } + } + #[inline] + pub unsafe fn set_color_raw(this: *mut Self, val: ::std::os::raw::c_uchar) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 4usize, + 4u8, + val as u64, + ) + } + } + #[inline] + pub fn weedsBonus(&self) -> ::std::os::raw::c_ushort { + unsafe { ::std::mem::transmute(self._bitfield_1.get(8usize, 3u8) as u16) } + } + #[inline] + pub fn set_weedsBonus(&mut self, val: ::std::os::raw::c_ushort) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(8usize, 3u8, val as u64) + } + } + #[inline] + pub unsafe fn weedsBonus_raw(this: *const Self) -> ::std::os::raw::c_ushort { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 8usize, 3u8) + as u16, + ) + } + } + #[inline] + pub unsafe fn set_weedsBonus_raw(this: *mut Self, val: ::std::os::raw::c_ushort) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 8usize, + 3u8, + val as u64, + ) + } + } + #[inline] + pub fn pestsBonus(&self) -> ::std::os::raw::c_ushort { + unsafe { ::std::mem::transmute(self._bitfield_1.get(11usize, 3u8) as u16) } + } + #[inline] + pub fn set_pestsBonus(&mut self, val: ::std::os::raw::c_ushort) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(11usize, 3u8, val as u64) + } + } + #[inline] + pub unsafe fn pestsBonus_raw(this: *const Self) -> ::std::os::raw::c_ushort { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 11usize, 3u8) + as u16, + ) + } + } + #[inline] + pub unsafe fn set_pestsBonus_raw(this: *mut Self, val: ::std::os::raw::c_ushort) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 11usize, + 3u8, + val as u64, + ) + } + } + #[inline] + pub fn size(&self) -> ::std::os::raw::c_ushort { + unsafe { ::std::mem::transmute(self._bitfield_1.get(14usize, 10u8) as u16) } + } + #[inline] + pub fn set_size(&mut self, val: ::std::os::raw::c_ushort) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(14usize, 10u8, val as u64) + } + } + #[inline] + pub unsafe fn size_raw(this: *const Self) -> ::std::os::raw::c_ushort { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 14usize, 10u8) + as u16, + ) + } + } + #[inline] + pub unsafe fn set_size_raw(this: *mut Self, val: ::std::os::raw::c_ushort) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit< + [u8; 3usize], + >>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 14usize, + 10u8, + val as u64, + ) + } + } + #[inline] + pub fn new_bitfield_1( + firmness: ::std::os::raw::c_uchar, + color: ::std::os::raw::c_uchar, + weedsBonus: ::std::os::raw::c_ushort, + pestsBonus: ::std::os::raw::c_ushort, + size: ::std::os::raw::c_ushort, + ) -> __BindgenBitfieldUnit<[u8; 3usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 3usize]> = Default::default(); + __bindgen_bitfield_unit + .set( + 0usize, + 4u8, + { + let firmness: u8 = unsafe { ::std::mem::transmute(firmness) }; + firmness as u64 + }, + ); + __bindgen_bitfield_unit + .set( + 4usize, + 4u8, + { + let color: u8 = unsafe { ::std::mem::transmute(color) }; + color as u64 + }, + ); + __bindgen_bitfield_unit + .set( + 8usize, + 3u8, + { + let weedsBonus: u16 = unsafe { ::std::mem::transmute(weedsBonus) }; + weedsBonus as u64 + }, + ); + __bindgen_bitfield_unit + .set( + 11usize, + 3u8, + { + let pestsBonus: u16 = unsafe { ::std::mem::transmute(pestsBonus) }; + pestsBonus as u64 + }, + ); + __bindgen_bitfield_unit + .set( + 14usize, + 10u8, + { + let size: u16 = unsafe { ::std::mem::transmute(size) }; + size as u64 + }, + ); + __bindgen_bitfield_unit + } + #[inline] + pub fn minYield(&self) -> ::std::os::raw::c_uchar { + unsafe { ::std::mem::transmute(self._bitfield_2.get(0usize, 4u8) as u8) } + } + #[inline] + pub fn set_minYield(&mut self, val: ::std::os::raw::c_uchar) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_2.set(0usize, 4u8, val as u64) + } + } + #[inline] + pub unsafe fn minYield_raw(this: *const Self) -> ::std::os::raw::c_uchar { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_2), 0usize, 4u8) as u8, + ) + } + } + #[inline] + pub unsafe fn set_minYield_raw(this: *mut Self, val: ::std::os::raw::c_uchar) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_2), + 0usize, + 4u8, + val as u64, + ) + } + } + #[inline] + pub fn waterBonus(&self) -> ::std::os::raw::c_uchar { + unsafe { ::std::mem::transmute(self._bitfield_2.get(4usize, 4u8) as u8) } + } + #[inline] + pub fn set_waterBonus(&mut self, val: ::std::os::raw::c_uchar) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_2.set(4usize, 4u8, val as u64) + } + } + #[inline] + pub unsafe fn waterBonus_raw(this: *const Self) -> ::std::os::raw::c_uchar { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_2), 4usize, 4u8) as u8, + ) + } + } + #[inline] + pub unsafe fn set_waterBonus_raw(this: *mut Self, val: ::std::os::raw::c_uchar) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_2), + 4usize, + 4u8, + val as u64, + ) + } + } + #[inline] + pub fn new_bitfield_2( + minYield: ::std::os::raw::c_uchar, + waterBonus: ::std::os::raw::c_uchar, + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default(); + __bindgen_bitfield_unit + .set( + 0usize, + 4u8, + { + let minYield: u8 = unsafe { ::std::mem::transmute(minYield) }; + minYield as u64 + }, + ); + __bindgen_bitfield_unit + .set( + 4usize, + 4u8, + { + let waterBonus: u8 = unsafe { ::std::mem::transmute(waterBonus) }; + waterBonus as u64 + }, + ); + __bindgen_bitfield_unit + } +} diff --git a/bindgen-tests/tests/expectations/tests/bitfield_pragma_packed.rs b/bindgen-tests/tests/expectations/tests/bitfield_pragma_packed.rs index 8869593ed5..6f9adcb5ab 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield_pragma_packed.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield_pragma_packed.rs @@ -148,7 +148,6 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Struct { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -394,7 +393,7 @@ impl Struct { #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Inner { - pub _bitfield_align_1: [u16; 0], + pub _bindgen_align: [u16; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/blocklist_bitfield_unit.rs b/bindgen-tests/tests/expectations/tests/blocklist_bitfield_unit.rs index fc9f9a38c7..77c263e3cc 100644 --- a/bindgen-tests/tests/expectations/tests/blocklist_bitfield_unit.rs +++ b/bindgen-tests/tests/expectations/tests/blocklist_bitfield_unit.rs @@ -6,7 +6,6 @@ use bitfields::*; #[derive(Debug, Default, Copy, Clone)] pub struct C { pub x: ::std::os::raw::c_uchar, - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub baz: ::std::os::raw::c_uint, } diff --git a/bindgen-tests/tests/expectations/tests/default_visibility_crate.rs b/bindgen-tests/tests/expectations/tests/default_visibility_crate.rs index aeb6a717f6..aeefb2e0f9 100644 --- a/bindgen-tests/tests/expectations/tests/default_visibility_crate.rs +++ b/bindgen-tests/tests/expectations/tests/default_visibility_crate.rs @@ -154,7 +154,6 @@ pub struct Point { #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Color { - pub(crate) _bitfield_align_1: [u8; 0], pub(crate) _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, } impl Color { diff --git a/bindgen-tests/tests/expectations/tests/default_visibility_private.rs b/bindgen-tests/tests/expectations/tests/default_visibility_private.rs index 4ee26721b0..dceed75e36 100644 --- a/bindgen-tests/tests/expectations/tests/default_visibility_private.rs +++ b/bindgen-tests/tests/expectations/tests/default_visibility_private.rs @@ -154,7 +154,6 @@ pub struct Point { #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Color { - _bitfield_align_1: [u8; 0], _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, } impl Color { diff --git a/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs b/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs index e676f6470d..f43be84bb0 100644 --- a/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs +++ b/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs @@ -154,7 +154,6 @@ pub struct Point { #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Color { - _bitfield_align_1: [u8; 0], _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, } impl Color { diff --git a/bindgen-tests/tests/expectations/tests/derive-bitfield-method-same-name.rs b/bindgen-tests/tests/expectations/tests/derive-bitfield-method-same-name.rs index 05e66a72bc..c2a9d33ca6 100644 --- a/bindgen-tests/tests/expectations/tests/derive-bitfield-method-same-name.rs +++ b/bindgen-tests/tests/expectations/tests/derive-bitfield-method-same-name.rs @@ -94,7 +94,6 @@ where #[derive(Copy, Clone)] pub struct Foo { pub large: [::std::os::raw::c_int; 33usize], - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>, pub __bindgen_padding_0: u16, } diff --git a/bindgen-tests/tests/expectations/tests/derive-debug-bitfield-1-51.rs b/bindgen-tests/tests/expectations/tests/derive-debug-bitfield-1-51.rs index 351d3b31e5..c5eed87ae5 100644 --- a/bindgen-tests/tests/expectations/tests/derive-debug-bitfield-1-51.rs +++ b/bindgen-tests/tests/expectations/tests/derive-debug-bitfield-1-51.rs @@ -148,7 +148,6 @@ where #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct C { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub large_array: [::std::os::raw::c_int; 50usize], } diff --git a/bindgen-tests/tests/expectations/tests/derive-debug-bitfield-core.rs b/bindgen-tests/tests/expectations/tests/derive-debug-bitfield-core.rs index edcb4e2a02..baeb87545d 100644 --- a/bindgen-tests/tests/expectations/tests/derive-debug-bitfield-core.rs +++ b/bindgen-tests/tests/expectations/tests/derive-debug-bitfield-core.rs @@ -91,7 +91,6 @@ where #[repr(C)] #[derive(Copy, Clone)] pub struct C { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub large_array: [::std::os::raw::c_int; 50usize], } diff --git a/bindgen-tests/tests/expectations/tests/derive-debug-bitfield.rs b/bindgen-tests/tests/expectations/tests/derive-debug-bitfield.rs index e266880509..e414b6fa32 100644 --- a/bindgen-tests/tests/expectations/tests/derive-debug-bitfield.rs +++ b/bindgen-tests/tests/expectations/tests/derive-debug-bitfield.rs @@ -90,7 +90,6 @@ where #[repr(C)] #[derive(Copy, Clone)] pub struct C { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub large_array: [::std::os::raw::c_int; 50usize], } diff --git a/bindgen-tests/tests/expectations/tests/derive-partialeq-bitfield.rs b/bindgen-tests/tests/expectations/tests/derive-partialeq-bitfield.rs index eaf3f45e5f..7bcdce32a3 100644 --- a/bindgen-tests/tests/expectations/tests/derive-partialeq-bitfield.rs +++ b/bindgen-tests/tests/expectations/tests/derive-partialeq-bitfield.rs @@ -90,7 +90,6 @@ where #[repr(C)] #[derive(Copy, Clone)] pub struct C { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub large_array: [::std::os::raw::c_int; 50usize], } diff --git a/bindgen-tests/tests/expectations/tests/divide-by-zero-in-struct-layout.rs b/bindgen-tests/tests/expectations/tests/divide-by-zero-in-struct-layout.rs index e01a9b3c72..37139d3136 100644 --- a/bindgen-tests/tests/expectations/tests/divide-by-zero-in-struct-layout.rs +++ b/bindgen-tests/tests/expectations/tests/divide-by-zero-in-struct-layout.rs @@ -148,7 +148,6 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct WithBitfield { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub a: ::std::os::raw::c_uint, } @@ -162,7 +161,6 @@ impl WithBitfield { #[repr(C, packed)] #[derive(Debug, Default, Copy, Clone)] pub struct WithBitfieldAndAttrPacked { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub a: ::std::os::raw::c_uint, } @@ -176,7 +174,6 @@ impl WithBitfieldAndAttrPacked { #[repr(C, packed)] #[derive(Debug, Default, Copy, Clone)] pub struct WithBitfieldAndPacked { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub a: ::std::os::raw::c_uint, } diff --git a/bindgen-tests/tests/expectations/tests/field-visibility-callback.rs b/bindgen-tests/tests/expectations/tests/field-visibility-callback.rs index aebc04f03b..99ca3d4b9b 100644 --- a/bindgen-tests/tests/expectations/tests/field-visibility-callback.rs +++ b/bindgen-tests/tests/expectations/tests/field-visibility-callback.rs @@ -150,7 +150,6 @@ where pub struct my_struct { pub a: ::std::os::raw::c_int, private_b: ::std::os::raw::c_int, - _bitfield_align_1: [u8; 0], _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, __bindgen_padding_0: [u8; 3usize], } diff --git a/bindgen-tests/tests/expectations/tests/field-visibility.rs b/bindgen-tests/tests/expectations/tests/field-visibility.rs index 3e43755a57..13a1d9a543 100644 --- a/bindgen-tests/tests/expectations/tests/field-visibility.rs +++ b/bindgen-tests/tests/expectations/tests/field-visibility.rs @@ -146,10 +146,9 @@ where } } #[repr(C)] -#[repr(align(4))] #[derive(Debug, Default, Copy, Clone)] pub struct my_struct1 { - _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u32; 0], _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, __bindgen_padding_0: [u8; 3usize], } @@ -211,10 +210,9 @@ impl my_struct1 { } } #[repr(C)] -#[repr(align(4))] #[derive(Debug, Default, Copy, Clone)] pub struct my_struct2 { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u32; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub __bindgen_padding_0: [u8; 3usize], } diff --git a/bindgen-tests/tests/expectations/tests/incomplete-array-padding.rs b/bindgen-tests/tests/expectations/tests/incomplete-array-padding.rs index 6e9f6e7753..a90fe54bf3 100644 --- a/bindgen-tests/tests/expectations/tests/incomplete-array-padding.rs +++ b/bindgen-tests/tests/expectations/tests/incomplete-array-padding.rs @@ -178,7 +178,6 @@ impl ::std::fmt::Debug for __IncompleteArrayField { #[repr(C)] #[derive(Debug)] pub struct foo { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub b: __IncompleteArrayField<*mut ::std::os::raw::c_void>, } diff --git a/bindgen-tests/tests/expectations/tests/issue-1034.rs b/bindgen-tests/tests/expectations/tests/issue-1034.rs index 1034520c48..90cc768a94 100644 --- a/bindgen-tests/tests/expectations/tests/issue-1034.rs +++ b/bindgen-tests/tests/expectations/tests/issue-1034.rs @@ -148,7 +148,6 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct S2 { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs b/bindgen-tests/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs index 3d14c81a77..50e9283b5a 100644 --- a/bindgen-tests/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs +++ b/bindgen-tests/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs @@ -148,7 +148,6 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct S1 { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 3usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/issue-1947.rs b/bindgen-tests/tests/expectations/tests/issue-1947.rs index cceb42d8c5..795b033a12 100644 --- a/bindgen-tests/tests/expectations/tests/issue-1947.rs +++ b/bindgen-tests/tests/expectations/tests/issue-1947.rs @@ -150,11 +150,10 @@ pub type U16 = ::std::os::raw::c_ushort; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct V56AMDY { - pub _bitfield_align_1: [u16; 0], + pub _bindgen_align: [u16; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>, pub MADK: U8, pub MABR: U8, - pub _bitfield_align_2: [u16; 0], pub _bitfield_2: __BindgenBitfieldUnit<[u8; 3usize]>, pub _rB_: U8, } diff --git a/bindgen-tests/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs b/bindgen-tests/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs index 4e79cfdf71..bc1951e7d1 100644 --- a/bindgen-tests/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs +++ b/bindgen-tests/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs @@ -149,7 +149,7 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Foo { - pub _bitfield_align_1: [u64; 0], + pub _bindgen_align: [u64; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 32usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/issue-743.rs b/bindgen-tests/tests/expectations/tests/issue-743.rs new file mode 100644 index 0000000000..af3eb5bf6e --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/issue-743.rs @@ -0,0 +1,225 @@ +#![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 { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + fn extract_bit(byte: u8, index: usize) -> bool { + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[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]; + Self::extract_bit(byte, index) + } + #[inline] + pub unsafe fn raw_get_bit(this: *const Self, index: usize) -> bool { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = unsafe { + *(core::ptr::addr_of!((*this).storage) as *const u8) + .offset(byte_index as isize) + }; + Self::extract_bit(byte, index) + } + #[inline] + fn change_bit(byte: u8, index: usize, val: bool) -> u8 { + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { byte | mask } else { byte & !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]; + *byte = Self::change_bit(*byte, index, val); + } + #[inline] + pub unsafe fn raw_set_bit(this: *mut Self, index: usize, val: bool) { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = unsafe { + (core::ptr::addr_of_mut!((*this).storage) as *mut u8) + .offset(byte_index as isize) + }; + unsafe { *byte = Self::change_bit(*byte, index, val) }; + } + #[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) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub unsafe fn raw_get(this: *const Self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::(), + ); + let mut val = 0; + for i in 0..(bit_width as usize) { + if unsafe { Self::raw_get_bit(this, i + bit_offset) } { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + 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; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } + #[inline] + pub unsafe fn raw_set(this: *mut Self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::(), + ); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + unsafe { Self::raw_set_bit(this, index + bit_offset, val_bit_is_set) }; + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct S { + pub p: *mut ::std::os::raw::c_void, + pub b: bool, + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>, + pub __bindgen_padding_0: [u8; 5usize], +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of S"][::std::mem::size_of::() - 16usize]; + ["Alignment of S"][::std::mem::align_of::() - 8usize]; + ["Offset of field: S::p"][::std::mem::offset_of!(S, p) - 0usize]; + ["Offset of field: S::b"][::std::mem::offset_of!(S, b) - 8usize]; +}; +impl Default for S { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl S { + #[inline] + pub fn u(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 16u8) as u32) } + } + #[inline] + pub fn set_u(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 16u8, val as u64) + } + } + #[inline] + pub unsafe fn u_raw(this: *const Self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 2usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 0usize, 16u8) + as u32, + ) + } + } + #[inline] + pub unsafe fn set_u_raw(this: *mut Self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + <__BindgenBitfieldUnit< + [u8; 2usize], + >>::raw_set( + ::std::ptr::addr_of_mut!((*this)._bitfield_1), + 0usize, + 16u8, + val as u64, + ) + } + } + #[inline] + pub fn new_bitfield_1( + u: ::std::os::raw::c_uint, + ) -> __BindgenBitfieldUnit<[u8; 2usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize]> = Default::default(); + __bindgen_bitfield_unit + .set( + 0usize, + 16u8, + { + let u: u32 = unsafe { ::std::mem::transmute(u) }; + u as u64 + }, + ); + __bindgen_bitfield_unit + } +} diff --git a/bindgen-tests/tests/expectations/tests/issue-816.rs b/bindgen-tests/tests/expectations/tests/issue-816.rs index 56e719238b..b1494afede 100644 --- a/bindgen-tests/tests/expectations/tests/issue-816.rs +++ b/bindgen-tests/tests/expectations/tests/issue-816.rs @@ -146,10 +146,9 @@ where } } #[repr(C)] -#[repr(align(4))] #[derive(Debug, Default, Copy, Clone)] pub struct capabilities { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u32; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 16usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs index 7dd23241e9..dc0ef8ed7f 100644 --- a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs +++ b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs @@ -245,7 +245,7 @@ pub union jsval_layout { #[repr(C)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct jsval_layout__bindgen_ty_1 { - pub _bitfield_align_1: [u64; 0], + pub _bindgen_align: [u64; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/layout_align.rs b/bindgen-tests/tests/expectations/tests/layout_align.rs index 18662d4c83..a942adb8f2 100644 --- a/bindgen-tests/tests/expectations/tests/layout_align.rs +++ b/bindgen-tests/tests/expectations/tests/layout_align.rs @@ -219,12 +219,11 @@ impl Default for rte_kni_fifo { } } #[repr(C)] -#[repr(align(8))] #[derive(Debug, Default, Copy, Clone)] pub struct rte_eth_link { + pub _bindgen_align: [u64; 0], ///< ETH_SPEED_NUM_ pub link_speed: u32, - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub __bindgen_padding_0: [u8; 3usize], } diff --git a/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs b/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs index 4a62ddbea3..2686d8f5fa 100644 --- a/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs +++ b/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs @@ -151,7 +151,6 @@ pub struct rte_eth_rxmode { pub max_rx_pkt_len: u32, ///< hdr buf size (header_split enabled). pub split_hdr_size: u16, - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>, } #[test] @@ -425,7 +424,6 @@ pub struct rte_eth_txmode { ///< TX multi-queues mode. pub mq_mode: rte_eth_tx_mq_mode, pub pvid: u16, - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub __bindgen_padding_0: u8, } diff --git a/bindgen-tests/tests/expectations/tests/layout_mbuf.rs b/bindgen-tests/tests/expectations/tests/layout_mbuf.rs index cb3698812b..ce6c58e39e 100644 --- a/bindgen-tests/tests/expectations/tests/layout_mbuf.rs +++ b/bindgen-tests/tests/expectations/tests/layout_mbuf.rs @@ -259,10 +259,9 @@ pub union rte_mbuf__bindgen_ty_2 { pub __bindgen_anon_1: rte_mbuf__bindgen_ty_2__bindgen_ty_1, } #[repr(C)] -#[repr(align(4))] #[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] pub struct rte_mbuf__bindgen_ty_2__bindgen_ty_1 { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u32; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -820,11 +819,11 @@ pub union rte_mbuf__bindgen_ty_5 { pub __bindgen_anon_1: rte_mbuf__bindgen_ty_5__bindgen_ty_1, } #[repr(C)] -#[repr(align(8))] #[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] pub struct rte_mbuf__bindgen_ty_5__bindgen_ty_1 { - pub _bitfield_align_1: [u16; 0], + pub _bindgen_align: [u64; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 7usize]>, + pub __bindgen_padding_0: u8, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { diff --git a/bindgen-tests/tests/expectations/tests/only_bitfields.rs b/bindgen-tests/tests/expectations/tests/only_bitfields.rs index 3aedce1e3f..9a73fc2fee 100644 --- a/bindgen-tests/tests/expectations/tests/only_bitfields.rs +++ b/bindgen-tests/tests/expectations/tests/only_bitfields.rs @@ -148,7 +148,6 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct C { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/packed-bitfield.rs b/bindgen-tests/tests/expectations/tests/packed-bitfield.rs index 4e3918f558..b5a734454a 100644 --- a/bindgen-tests/tests/expectations/tests/packed-bitfield.rs +++ b/bindgen-tests/tests/expectations/tests/packed-bitfield.rs @@ -148,7 +148,6 @@ where #[repr(C, packed)] #[derive(Debug, Default, Copy, Clone)] pub struct Date { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 3usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/private_fields.rs b/bindgen-tests/tests/expectations/tests/private_fields.rs index a5d9e84499..abb2886d39 100644 --- a/bindgen-tests/tests/expectations/tests/private_fields.rs +++ b/bindgen-tests/tests/expectations/tests/private_fields.rs @@ -159,10 +159,9 @@ const _: () = { ["Offset of field: PubPriv::y"][::std::mem::offset_of!(PubPriv, y) - 4usize]; }; #[repr(C)] -#[repr(align(4))] #[derive(Debug, Default, Copy, Clone)] pub struct PrivateBitFields { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u32; 0], _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub __bindgen_padding_0: [u8; 3usize], } @@ -274,10 +273,9 @@ impl PrivateBitFields { } } #[repr(C)] -#[repr(align(4))] #[derive(Debug, Default, Copy, Clone)] pub struct PublicBitFields { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u32; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub __bindgen_padding_0: [u8; 3usize], } @@ -387,10 +385,9 @@ impl PublicBitFields { } } #[repr(C)] -#[repr(align(4))] #[derive(Debug, Default, Copy, Clone)] pub struct MixedBitFields { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u32; 0], _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub __bindgen_padding_0: [u8; 3usize], } @@ -628,7 +625,6 @@ pub struct Override { ///
b: ::std::os::raw::c_uint, private_c: ::std::os::raw::c_uint, - pub _bitfield_align_1: [u8; 0], _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>, pub __bindgen_padding_0: u16, } diff --git a/bindgen-tests/tests/expectations/tests/redundant-packed-and-align.rs b/bindgen-tests/tests/expectations/tests/redundant-packed-and-align.rs index c01762ca98..05401e52ca 100644 --- a/bindgen-tests/tests/expectations/tests/redundant-packed-and-align.rs +++ b/bindgen-tests/tests/expectations/tests/redundant-packed-and-align.rs @@ -166,11 +166,10 @@ const _: () = { ][::std::mem::offset_of!(redundant_packed, b) - 4usize]; }; #[repr(C)] -#[repr(align(8))] #[derive(Debug, Default, Copy, Clone)] pub struct redundant_packed_bitfield { + pub _bindgen_align: [u64; 0], pub a: [u8; 3usize], - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub c: u32, } diff --git a/bindgen-tests/tests/expectations/tests/struct_with_bitfields.rs b/bindgen-tests/tests/expectations/tests/struct_with_bitfields.rs index 23588ee7da..a294c871d3 100644 --- a/bindgen-tests/tests/expectations/tests/struct_with_bitfields.rs +++ b/bindgen-tests/tests/expectations/tests/struct_with_bitfields.rs @@ -148,10 +148,8 @@ where #[repr(C)] #[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] pub struct bitfield { - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, pub e: ::std::os::raw::c_int, - pub _bitfield_align_2: [u32; 0], pub _bitfield_2: __BindgenBitfieldUnit<[u8; 8usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/timex.rs b/bindgen-tests/tests/expectations/tests/timex.rs index 3d25971315..f73b608de2 100644 --- a/bindgen-tests/tests/expectations/tests/timex.rs +++ b/bindgen-tests/tests/expectations/tests/timex.rs @@ -149,7 +149,6 @@ where #[derive(Debug, Copy, Clone)] pub struct timex { pub tai: ::std::os::raw::c_int, - pub _bitfield_align_1: [u8; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 44usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -171,7 +170,6 @@ impl Default for timex { #[derive(Debug, Copy, Clone)] pub struct timex_named { pub tai: ::std::os::raw::c_int, - pub _bitfield_align_1: [u32; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 44usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/union_bitfield.rs b/bindgen-tests/tests/expectations/tests/union_bitfield.rs index 70da5c3b02..8df0724738 100644 --- a/bindgen-tests/tests/expectations/tests/union_bitfield.rs +++ b/bindgen-tests/tests/expectations/tests/union_bitfield.rs @@ -146,10 +146,9 @@ where } } #[repr(C)] -#[repr(align(4))] #[derive(Copy, Clone)] pub union U4 { - pub _bitfield_align_1: [u8; 0], + pub _bindgen_align: [u32; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -223,8 +222,8 @@ impl U4 { #[repr(C)] #[derive(Copy, Clone)] pub union B { - pub _bitfield_align_1: [u32; 0], - pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, + pub _bindgen_align: [u32; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { @@ -257,7 +256,7 @@ impl B { unsafe { ::std::mem::transmute( <__BindgenBitfieldUnit< - [u8; 4usize], + [u8; 1usize], >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 0usize, 31u8) as u32, ) @@ -268,7 +267,7 @@ impl B { unsafe { let val: u32 = ::std::mem::transmute(val); <__BindgenBitfieldUnit< - [u8; 4usize], + [u8; 1usize], >>::raw_set( ::std::ptr::addr_of_mut!((*this)._bitfield_1), 0usize, @@ -279,13 +278,13 @@ impl B { } #[inline] pub fn bar(&self) -> ::std::os::raw::c_uchar { - unsafe { ::std::mem::transmute(self._bitfield_1.get(31usize, 1u8) as u8) } + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u8) } } #[inline] pub fn set_bar(&mut self, val: ::std::os::raw::c_uchar) { unsafe { let val: u8 = ::std::mem::transmute(val); - self._bitfield_1.set(31usize, 1u8, val as u64) + self._bitfield_1.set(0usize, 1u8, val as u64) } } #[inline] @@ -293,9 +292,8 @@ impl B { unsafe { ::std::mem::transmute( <__BindgenBitfieldUnit< - [u8; 4usize], - >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 31usize, 1u8) - as u8, + [u8; 1usize], + >>::raw_get(::std::ptr::addr_of!((*this)._bitfield_1), 0usize, 1u8) as u8, ) } } @@ -304,10 +302,10 @@ impl B { unsafe { let val: u8 = ::std::mem::transmute(val); <__BindgenBitfieldUnit< - [u8; 4usize], + [u8; 1usize], >>::raw_set( ::std::ptr::addr_of_mut!((*this)._bitfield_1), - 31usize, + 0usize, 1u8, val as u64, ) @@ -317,8 +315,8 @@ impl B { pub fn new_bitfield_1( foo: ::std::os::raw::c_uint, bar: ::std::os::raw::c_uchar, - ) -> __BindgenBitfieldUnit<[u8; 4usize]> { - let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 4usize]> = Default::default(); + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default(); __bindgen_bitfield_unit .set( 0usize, @@ -330,7 +328,7 @@ impl B { ); __bindgen_bitfield_unit .set( - 31usize, + 0usize, 1u8, { let bar: u8 = unsafe { ::std::mem::transmute(bar) }; diff --git a/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield.rs b/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield.rs index dd1a55e9b5..a1b61c035d 100644 --- a/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield.rs +++ b/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield.rs @@ -154,7 +154,7 @@ pub union foo { #[repr(C)] #[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] pub struct foo__bindgen_ty_1 { - pub _bitfield_align_1: [u32; 0], + pub _bindgen_align: [u32; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/weird_bitfields.rs b/bindgen-tests/tests/expectations/tests/weird_bitfields.rs index 17accb01d9..ca8d84520b 100644 --- a/bindgen-tests/tests/expectations/tests/weird_bitfields.rs +++ b/bindgen-tests/tests/expectations/tests/weird_bitfields.rs @@ -156,7 +156,6 @@ pub enum nsStyleSVGOpacitySource { #[derive(Debug, Copy, Clone)] pub struct Weird { pub mStrokeDasharrayLength: ::std::os::raw::c_uint, - pub _bitfield_align_1: [u16; 0], pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, pub mClipRule: ::std::os::raw::c_uchar, pub mColorInterpolation: ::std::os::raw::c_uchar, @@ -169,7 +168,6 @@ pub struct Weird { pub mStrokeLinejoin: ::std::os::raw::c_uchar, pub mTextAnchor: ::std::os::raw::c_uchar, pub mTextRendering: ::std::os::raw::c_uchar, - pub _bitfield_align_2: [u8; 0], pub _bitfield_2: __BindgenBitfieldUnit<[u8; 2usize]>, pub __bindgen_padding_0: [u8; 3usize], } diff --git a/bindgen-tests/tests/headers/bitfield-linux-32.hpp b/bindgen-tests/tests/headers/bitfield-linux-32.hpp index b9a480df15..71ee6a7e1d 100644 --- a/bindgen-tests/tests/headers/bitfield-linux-32.hpp +++ b/bindgen-tests/tests/headers/bitfield-linux-32.hpp @@ -1,4 +1,4 @@ -// bindgen-flags: -- --target=i586-unknown-linux +// bindgen-flags: --no-layout-tests -- --target=i586-unknown-linux typedef unsigned long long uint64_t; diff --git a/bindgen-tests/tests/headers/bitfield-template.hpp b/bindgen-tests/tests/headers/bitfield-template.hpp new file mode 100644 index 0000000000..664199b9c0 --- /dev/null +++ b/bindgen-tests/tests/headers/bitfield-template.hpp @@ -0,0 +1,4 @@ +template struct foo { + T member; + bool b : 8; +}; diff --git a/bindgen-tests/tests/headers/bitfield_pack_offset.h b/bindgen-tests/tests/headers/bitfield_pack_offset.h new file mode 100644 index 0000000000..5118a64642 --- /dev/null +++ b/bindgen-tests/tests/headers/bitfield_pack_offset.h @@ -0,0 +1,21 @@ +struct A { + const unsigned char name[7]; /* 0 7 */ + unsigned char firmness:4; /* 7: 0 1 */ + unsigned char color:4; /* 7: 4 1 */ + unsigned short weedsBonus:3; /* 8: 0 2 */ + unsigned short pestsBonus:3; /* 8: 3 2 */ + unsigned short size:10; /* 8: 6 2 */ + unsigned char maxYield; /* 10 1 */ + unsigned char minYield:4; /* 11: 0 1 */ + unsigned char waterBonus:4; /* 11: 4 1 */ + + /* XXX 4 bytes hole, try to pack */ + + const unsigned char * description1; /* 16 8 */ + + /* size: 24, cachelines: 1, members: 10 */ + /* sum members: 16, holes: 1, sum holes: 4 */ + /* sum bitfield members: 32 bits (4 bytes) */ + /* last cacheline: 24 bytes */ +}; + diff --git a/bindgen-tests/tests/headers/issue-743.h b/bindgen-tests/tests/headers/issue-743.h new file mode 100644 index 0000000000..1f8e0ccd78 --- /dev/null +++ b/bindgen-tests/tests/headers/issue-743.h @@ -0,0 +1,6 @@ + +struct S { + void *p; + _Bool b; + unsigned u : 16; +}; \ No newline at end of file diff --git a/bindgen-tests/tests/headers/union_bitfield.h b/bindgen-tests/tests/headers/union_bitfield.h index 990729574a..4592a8973a 100644 --- a/bindgen-tests/tests/headers/union_bitfield.h +++ b/bindgen-tests/tests/headers/union_bitfield.h @@ -1,10 +1,10 @@ // bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq union U4 { - unsigned derp : 1; + unsigned int derp:1; /* 0: 0 4 */ }; union B { - unsigned foo : 31; - unsigned char bar : 1; + unsigned int foo:31; /* 0: 0 4 */ + unsigned char bar:1; /* 0: 0 1 */ }; diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index c0f461b326..5425962bac 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -1770,22 +1770,6 @@ impl FieldCodegen<'_> for BitfieldUnit { } }; - { - let align_field_name = format!("_bitfield_align_{}", self.nth()); - let align_field_ident = ctx.rust_ident(align_field_name); - let align_ty = match self.layout().align { - n if n >= 8 => quote! { u64 }, - 4 => quote! { u32 }, - 2 => quote! { u16 }, - _ => quote! { u8 }, - }; - let access_spec = access_specifier(visibility_kind); - let align_field = quote! { - #access_spec #align_field_ident: [#align_ty; 0], - }; - fields.extend(Some(align_field)); - } - let unit_field_name = format!("_bitfield_{}", self.nth()); let unit_field_ident = ctx.rust_ident(&unit_field_name); @@ -2428,10 +2412,24 @@ impl CodeGenerator for CompInfo { attributes.push(attributes::repr("C")); } - if true { - if let Some(explicit) = explicit_align { - // Ensure that the struct has the correct alignment even in - // presence of alignas. + // Ensure that the struct has the correct alignment even in presence of alignas and co. + if let Some(explicit) = explicit_align { + // If we need explicit alignment and can do it, we prefer to insert a dummy field at + // the beginning of the struct. This avoids hitting + // https://github.com/rust-lang/rust-bindgen/issues/2179 + // Do it for bitfields only for now for backwards compat. + if self.has_bitfields() && explicit <= 8 { + let align_ty = match explicit { + 8 => quote! { u64 }, + 4 => quote! { u32 }, + 2 => quote! { u16 }, + _ => quote! { u8 }, + }; + let align_field = quote! { + pub _bindgen_align: [#align_ty; 0], + }; + fields.insert(0, align_field); + } else { let explicit = helpers::ast_ty::int_expr(explicit as i64); attributes.push(quote! { #[repr(align(#explicit))] diff --git a/bindgen/codegen/struct_layout.rs b/bindgen/codegen/struct_layout.rs index 0d2e6a05c5..3dfd076c25 100644 --- a/bindgen/codegen/struct_layout.rs +++ b/bindgen/codegen/struct_layout.rs @@ -45,23 +45,6 @@ pub(crate) fn align_to(size: usize, align: usize) -> usize { size + align - rem } -/// Returns the lower power of two byte count that can hold at most n bits. -pub(crate) fn bytes_from_bits_pow2(mut n: usize) -> usize { - if n == 0 { - return 0; - } - - if n <= 8 { - return 1; - } - - if !n.is_power_of_two() { - n = n.next_power_of_two(); - } - - n / 8 -} - #[test] fn test_align_to() { assert_eq!(align_to(1, 1), 1); @@ -71,20 +54,6 @@ fn test_align_to() { assert_eq!(align_to(17, 4), 20); } -#[test] -fn test_bytes_from_bits_pow2() { - assert_eq!(bytes_from_bits_pow2(0), 0); - for i in 1..9 { - assert_eq!(bytes_from_bits_pow2(i), 1); - } - for i in 9..17 { - assert_eq!(bytes_from_bits_pow2(i), 2); - } - for i in 17..33 { - assert_eq!(bytes_from_bits_pow2(i), 4); - } -} - impl<'a> StructLayoutTracker<'a> { pub(crate) fn new( ctx: &'a BindgenContext, diff --git a/bindgen/ir/comp.rs b/bindgen/ir/comp.rs index 655e0f1fa5..c0860f9fe3 100644 --- a/bindgen/ir/comp.rs +++ b/bindgen/ir/comp.rs @@ -12,7 +12,7 @@ use super::template::TemplateParameters; use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT; use crate::clang; -use crate::codegen::struct_layout::{align_to, bytes_from_bits_pow2}; +use crate::codegen::struct_layout::align_to; use crate::ir::derive::CanDeriveCopy; use crate::parse::ParseError; use crate::HashMap; @@ -560,18 +560,12 @@ where fields: &mut E, bitfield_unit_count: &mut usize, unit_size_in_bits: usize, - unit_align_in_bits: usize, bitfields: Vec, - packed: bool, ) where E: Extend, { *bitfield_unit_count += 1; - let align = if packed { - 1 - } else { - bytes_from_bits_pow2(unit_align_in_bits) - }; + let align = 1; let size = align_to(unit_size_in_bits, 8) / 8; let layout = Layout::new(size, align); fields.extend(Some(Field::Bitfields(BitfieldUnit { @@ -581,70 +575,45 @@ where }))); } + // The offset we're in inside the struct, if we know it (we might not know it in presence of + // templates). + let mut start_offset_in_struct = 0; let mut max_align = 0; - let mut unfilled_bits_in_unit = 0; let mut unit_size_in_bits = 0; - let mut unit_align = 0; let mut bitfields_in_unit = vec![]; - // TODO(emilio): Determine this from attributes or pragma ms_struct - // directives. Also, perhaps we should check if the target is MSVC? - const is_ms_struct: bool = false; - + // TODO(emilio): Deal with ms_struct bitfield layout for MSVC? for bitfield in raw_bitfields { let bitfield_width = bitfield.bitfield_width().unwrap() as usize; let bitfield_layout = ctx.resolve_type(bitfield.ty()).layout(ctx).ok_or(())?; - let bitfield_size = bitfield_layout.size; let bitfield_align = bitfield_layout.align; + let bitfield_size = bitfield_layout.size; - let mut offset = unit_size_in_bits; - if !packed { - if is_ms_struct { - if unit_size_in_bits != 0 && - (bitfield_width == 0 || - bitfield_width > unfilled_bits_in_unit) - { - // We've reached the end of this allocation unit, so flush it - // and its bitfields. - unit_size_in_bits = - align_to(unit_size_in_bits, unit_align * 8); - flush_allocation_unit( - fields, - bitfield_unit_count, - unit_size_in_bits, - unit_align, - mem::take(&mut bitfields_in_unit), - packed, - ); + if unit_size_in_bits == 0 { + start_offset_in_struct = bitfield.offset().unwrap_or(0); + } - // Now we're working on a fresh bitfield allocation unit, so reset - // the current unit size and alignment. - offset = 0; - unit_align = 0; - } - } else if offset != 0 && - (bitfield_width == 0 || - (offset & (bitfield_align * 8 - 1)) + bitfield_width > - bitfield_size * 8) - { - offset = align_to(offset, bitfield_align * 8); - } + let mut offset_in_struct = + bitfield.offset().unwrap_or(unit_size_in_bits); + + // A zero-width field serves as alignment / padding. + if !packed && + offset_in_struct != 0 && + (bitfield_width == 0 || + (offset_in_struct & (bitfield_align * 8 - 1)) + + bitfield_width > + bitfield_size * 8) + { + offset_in_struct = align_to(offset_in_struct, bitfield_align * 8); } - // According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not - // affect the alignment of a structure or union". This makes sense: such - // bit-fields are only used for padding, and we can't perform an - // un-aligned read of something we can't read because we can't even name - // it. + // According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not affect the + // alignment of a structure or union". This makes sense: such bit-fields are only used for + // padding, and we can't perform an un-aligned read of something we can't read because we + // can't even name it. if bitfield.name().is_some() { max_align = cmp::max(max_align, bitfield_align); - - // NB: The `bitfield_width` here is completely, absolutely - // intentional. Alignment of the allocation unit is based on the - // maximum bitfield width, not (directly) on the bitfields' types' - // alignment. - unit_align = cmp::max(unit_align, bitfield_width); } // Always keep all bitfields around. While unnamed bitifields are used @@ -652,15 +621,12 @@ where // bitfields over their types size cause weird allocation size behavior from clang. // Therefore, all bitfields needed to be kept around in order to check for this // and make the struct opaque in this case - bitfields_in_unit.push(Bitfield::new(offset, bitfield)); - - unit_size_in_bits = offset + bitfield_width; - - // Compute what the physical unit's final size would be given what we - // have seen so far, and use that to compute how many bits are still - // available in the unit. - let data_size = align_to(unit_size_in_bits, bitfield_align * 8); - unfilled_bits_in_unit = data_size - unit_size_in_bits; + bitfields_in_unit.push(Bitfield::new( + offset_in_struct - start_offset_in_struct, + bitfield, + )); + unit_size_in_bits = + offset_in_struct - start_offset_in_struct + bitfield_width; } if unit_size_in_bits != 0 { @@ -669,9 +635,7 @@ where fields, bitfield_unit_count, unit_size_in_bits, - unit_align, bitfields_in_unit, - packed, ); } @@ -1181,7 +1145,8 @@ impl CompInfo { } } - fn has_bitfields(&self) -> bool { + /// Returns whether we have any bitfield within the struct. + pub(crate) fn has_bitfields(&self) -> bool { match self.fields { CompFields::Error => false, CompFields::After {