-
Notifications
You must be signed in to change notification settings - Fork 739
bindgen produces an E0588 when dealing with union and packed struct #1896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
It seems that runs error when packed struct has a union data |
minium reproduction code typedef union {
struct {
int a: 2;
};
} Union;
#pragma pack(1)
typedef struct {
Union u;
} PackStruct;
#pragma pack() /* automatically generated by rust-bindgen 0.55.1 */
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct __BindgenBitfieldUnit<Storage, Align> {
storage: Storage,
align: [Align; 0],
}
impl<Storage, Align> __BindgenBitfieldUnit<Storage, Align> {
#[inline]
pub const fn new(storage: Storage) -> Self {
Self { storage, align: [] }
}
}
impl<Storage, Align> __BindgenBitfieldUnit<Storage, Align>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
{
#[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 = if cfg!(target_endian = "big") {
7 - (index % 8)
} else {
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 = 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 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 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);
}
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union Union {
pub __bindgen_anon_1: Union__bindgen_ty_1,
_bindgen_union_align: u32,
}
#[repr(C)]
#[repr(align(4))]
#[derive(Debug, Copy, Clone)]
pub struct Union__bindgen_ty_1 {
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize], u8>,
pub __bindgen_padding_0: [u8; 3usize],
}
#[test]
fn bindgen_test_layout_Union__bindgen_ty_1() {
assert_eq!(
::std::mem::size_of::<Union__bindgen_ty_1>(),
4usize,
concat!("Size of: ", stringify!(Union__bindgen_ty_1))
);
assert_eq!(
::std::mem::align_of::<Union__bindgen_ty_1>(),
4usize,
concat!("Alignment of ", stringify!(Union__bindgen_ty_1))
);
}
impl Union__bindgen_ty_1 {
#[inline]
pub fn a(&self) -> ::std::os::raw::c_int {
unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 2u8) as u32) }
}
#[inline]
pub fn set_a(&mut self, val: ::std::os::raw::c_int) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(0usize, 2u8, val as u64)
}
}
#[inline]
pub fn new_bitfield_1(a: ::std::os::raw::c_int) -> __BindgenBitfieldUnit<[u8; 1usize], u8> {
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize], u8> =
Default::default();
__bindgen_bitfield_unit.set(0usize, 2u8, {
let a: u32 = unsafe { ::std::mem::transmute(a) };
a as u64
});
__bindgen_bitfield_unit
}
}
#[test]
fn bindgen_test_layout_Union() {
assert_eq!(
::std::mem::size_of::<Union>(),
4usize,
concat!("Size of: ", stringify!(Union))
);
assert_eq!(
::std::mem::align_of::<Union>(),
4usize,
concat!("Alignment of ", stringify!(Union))
);
}
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct PackStruct {
pub u: Union,
}
#[test]
fn bindgen_test_layout_PackStruct() {
assert_eq!(
::std::mem::size_of::<PackStruct>(),
4usize,
concat!("Size of: ", stringify!(PackStruct))
);
assert_eq!(
::std::mem::align_of::<PackStruct>(),
1usize,
concat!("Alignment of ", stringify!(PackStruct))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<PackStruct>())).u as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(PackStruct),
"::",
stringify!(u)
)
);
} error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> src/../out/binding.rs:148:1
|
148 | / pub struct PackStruct {
149 | | pub u: Union,
150 | | }
| |_^
|
note: `Union__bindgen_ty_1` has a `#[repr(align)]` attribute
--> src/../out/binding.rs:93:1
|
93 | / pub struct Union__bindgen_ty_1 {
94 | | pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize], u8>,
95 | | pub __bindgen_padding_0: [u8; 3usize],
96 | | }
| |_^
note: `PackStruct` contains a field of type `Union`
--> src/../out/binding.rs:149:9
|
149 | pub u: Union,
| ^
note: ...which contains a field of type `Union__bindgen_ty_1`
--> src/../out/binding.rs:87:9
|
87 | pub __bindgen_anon_1: Union__bindgen_ty_1,
| ^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0588`.
error: could not compile `bread-os-lib`.
To learn more, run the command again with --verbose. |
in #[repr(align(4))] |
I'm also experiencing a similar issue; haven't tracked down the exact code yet but attemping to make bindings to the latest version of https://github.com/vpzomtrrfrt/wiiuse-sys on Windows (but not Linux) fails. If needed I can provide instructions to reproduce. EDIT: Found that my issue could be resolved via the blacklists from here: #1556 |
So... generally this is kind of a rust bug, but in this case bindgen could avoid generating the I'll update the OP with the minimized test-case. Thanks @himself65! |
So the main issue is that something like: struct Foo {
int a: 2;
}; Needs explicit alignment because the bitfield we generate for something like this:
is this:
This is correct in the general case (because if you stash a For this specific case where the bitfield unit is the last field of the whole struct, we could bump the bitfield alignment up to the struct alignment, to avoid needing The relevant code is |
See #1896 (comment) for minimal repro, OP below:
Input C/C++ Header
Bindgen Invocation
Actual Results
rust-bindgen code
Expected Results
Build correctly
The text was updated successfully, but these errors were encountered: