bindgen produces an E0588 when dealing with union and packed struct #1896
Open
Description
opened on Oct 1, 2020
See #1896 (comment) for minimal repro, OP below:
Input C/C++ Header
typedef unsigned int UINT32;
typedef unsigned short UINT16;
typedef union {
struct {
UINT32 Revision: 8;
UINT32 ShiftPressed: 1;
UINT32 ControlPressed: 1;
UINT32 AltPressed: 1;
UINT32 LogoPressed: 1;
UINT32 MenuPressed: 1;
UINT32 SysReqPressed: 1;
UINT32 Reserved: 16;
UINT32 InputKeyCount: 2;
} Options;
UINT32 PackedValue;
} EFI_BOOT_KEY_DATA;
#pragma pack(1)
typedef struct {
EFI_BOOT_KEY_DATA KeyData;
UINT32 BootOptionCrc;
UINT16 BootOption;
} EFI_KEY_OPTION;
#pragma pack()
Bindgen Invocation
let bindings = bindgen::Builder::default()
.header("input.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUTPUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("binding.rs"))
.expect("Couldn't write bindings!");
Actual Results
> cargo build
Compiling bread-os-lib v0.0.1 (/home/himself65/Desktop/github/bread-os)
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> src/../out/binding.rs:303:1
|
303 | / pub struct EFI_KEY_OPTION {
304 | | #[doc = ""]
305 | | #[doc = " Specifies options about how the key will be processed."]
306 | | #[doc = ""]
... |
318 | | pub BootOption: UINT16,
319 | | }
| |_^
|
note: `EFI_BOOT_KEY_DATA__bindgen_ty_1` has a `#[repr(align)]` attribute
--> src/../out/binding.rs:99:1
|
99 | / pub struct EFI_BOOT_KEY_DATA__bindgen_ty_1 {
100 | | pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize], u16>,
101 | | }
| |_^
note: `EFI_KEY_OPTION` contains a field of type `EFI_BOOT_KEY_DATA`
--> src/../out/binding.rs:307:9
|
307 | pub KeyData: EFI_BOOT_KEY_DATA,
| ^^^^^^^
note: ...which contains a field of type `EFI_BOOT_KEY_DATA__bindgen_ty_1`
--> src/../out/binding.rs:92:9
|
92 | pub Options: EFI_BOOT_KEY_DATA__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.
rust-bindgen code
/* 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);
}
}
}
pub type UINT32 = ::std::os::raw::c_uint;
pub type UINT16 = ::std::os::raw::c_ushort;
#[doc = ""]
#[doc = " EFI Boot Key Data"]
#[doc = ""]
#[repr(C)]
#[derive(Copy, Clone)]
pub union EFI_BOOT_KEY_DATA {
pub Options: EFI_BOOT_KEY_DATA__bindgen_ty_1,
pub PackedValue: UINT32,
_bindgen_union_align: u32,
}
#[repr(C)]
#[repr(align(4))]
#[derive(Debug, Copy, Clone)]
pub struct EFI_BOOT_KEY_DATA__bindgen_ty_1 {
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize], u16>,
}
#[test]
fn bindgen_test_layout_EFI_BOOT_KEY_DATA__bindgen_ty_1() {
assert_eq!(
::std::mem::size_of::<EFI_BOOT_KEY_DATA__bindgen_ty_1>(),
4usize,
concat!("Size of: ", stringify!(EFI_BOOT_KEY_DATA__bindgen_ty_1))
);
assert_eq!(
::std::mem::align_of::<EFI_BOOT_KEY_DATA__bindgen_ty_1>(),
4usize,
concat!("Alignment of ", stringify!(EFI_BOOT_KEY_DATA__bindgen_ty_1))
);
}
impl EFI_BOOT_KEY_DATA__bindgen_ty_1 {
#[inline]
pub fn Revision(&self) -> UINT32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 8u8) as u32) }
}
#[inline]
pub fn set_Revision(&mut self, val: UINT32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(0usize, 8u8, val as u64)
}
}
#[inline]
pub fn ShiftPressed(&self) -> UINT32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(8usize, 1u8) as u32) }
}
#[inline]
pub fn set_ShiftPressed(&mut self, val: UINT32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(8usize, 1u8, val as u64)
}
}
#[inline]
pub fn ControlPressed(&self) -> UINT32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(9usize, 1u8) as u32) }
}
#[inline]
pub fn set_ControlPressed(&mut self, val: UINT32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(9usize, 1u8, val as u64)
}
}
#[inline]
pub fn AltPressed(&self) -> UINT32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(10usize, 1u8) as u32) }
}
#[inline]
pub fn set_AltPressed(&mut self, val: UINT32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(10usize, 1u8, val as u64)
}
}
#[inline]
pub fn LogoPressed(&self) -> UINT32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(11usize, 1u8) as u32) }
}
#[inline]
pub fn set_LogoPressed(&mut self, val: UINT32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(11usize, 1u8, val as u64)
}
}
#[inline]
pub fn MenuPressed(&self) -> UINT32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(12usize, 1u8) as u32) }
}
#[inline]
pub fn set_MenuPressed(&mut self, val: UINT32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(12usize, 1u8, val as u64)
}
}
#[inline]
pub fn SysReqPressed(&self) -> UINT32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(13usize, 1u8) as u32) }
}
#[inline]
pub fn set_SysReqPressed(&mut self, val: UINT32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(13usize, 1u8, val as u64)
}
}
#[inline]
pub fn Reserved(&self) -> UINT32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(14usize, 16u8) as u32) }
}
#[inline]
pub fn set_Reserved(&mut self, val: UINT32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(14usize, 16u8, val as u64)
}
}
#[inline]
pub fn InputKeyCount(&self) -> UINT32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(30usize, 2u8) as u32) }
}
#[inline]
pub fn set_InputKeyCount(&mut self, val: UINT32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(30usize, 2u8, val as u64)
}
}
#[inline]
pub fn new_bitfield_1(
Revision: UINT32,
ShiftPressed: UINT32,
ControlPressed: UINT32,
AltPressed: UINT32,
LogoPressed: UINT32,
MenuPressed: UINT32,
SysReqPressed: UINT32,
Reserved: UINT32,
InputKeyCount: UINT32,
) -> __BindgenBitfieldUnit<[u8; 4usize], u16> {
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 4usize], u16> =
Default::default();
__bindgen_bitfield_unit.set(0usize, 8u8, {
let Revision: u32 = unsafe { ::std::mem::transmute(Revision) };
Revision as u64
});
__bindgen_bitfield_unit.set(8usize, 1u8, {
let ShiftPressed: u32 = unsafe { ::std::mem::transmute(ShiftPressed) };
ShiftPressed as u64
});
__bindgen_bitfield_unit.set(9usize, 1u8, {
let ControlPressed: u32 = unsafe { ::std::mem::transmute(ControlPressed) };
ControlPressed as u64
});
__bindgen_bitfield_unit.set(10usize, 1u8, {
let AltPressed: u32 = unsafe { ::std::mem::transmute(AltPressed) };
AltPressed as u64
});
__bindgen_bitfield_unit.set(11usize, 1u8, {
let LogoPressed: u32 = unsafe { ::std::mem::transmute(LogoPressed) };
LogoPressed as u64
});
__bindgen_bitfield_unit.set(12usize, 1u8, {
let MenuPressed: u32 = unsafe { ::std::mem::transmute(MenuPressed) };
MenuPressed as u64
});
__bindgen_bitfield_unit.set(13usize, 1u8, {
let SysReqPressed: u32 = unsafe { ::std::mem::transmute(SysReqPressed) };
SysReqPressed as u64
});
__bindgen_bitfield_unit.set(14usize, 16u8, {
let Reserved: u32 = unsafe { ::std::mem::transmute(Reserved) };
Reserved as u64
});
__bindgen_bitfield_unit.set(30usize, 2u8, {
let InputKeyCount: u32 = unsafe { ::std::mem::transmute(InputKeyCount) };
InputKeyCount as u64
});
__bindgen_bitfield_unit
}
}
#[test]
fn bindgen_test_layout_EFI_BOOT_KEY_DATA() {
assert_eq!(
::std::mem::size_of::<EFI_BOOT_KEY_DATA>(),
4usize,
concat!("Size of: ", stringify!(EFI_BOOT_KEY_DATA))
);
assert_eq!(
::std::mem::align_of::<EFI_BOOT_KEY_DATA>(),
4usize,
concat!("Alignment of ", stringify!(EFI_BOOT_KEY_DATA))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<EFI_BOOT_KEY_DATA>())).Options as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(EFI_BOOT_KEY_DATA),
"::",
stringify!(Options)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<EFI_BOOT_KEY_DATA>())).PackedValue as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(EFI_BOOT_KEY_DATA),
"::",
stringify!(PackedValue)
)
);
}
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct EFI_KEY_OPTION {
#[doc = ""]
#[doc = " Specifies options about how the key will be processed."]
#[doc = ""]
pub KeyData: EFI_BOOT_KEY_DATA,
#[doc = ""]
#[doc = " The CRC-32 which should match the CRC-32 of the entire EFI_LOAD_OPTION to"]
#[doc = " which BootOption refers. If the CRC-32s do not match this value, then this key"]
#[doc = " option is ignored."]
#[doc = ""]
pub BootOptionCrc: UINT32,
#[doc = ""]
#[doc = " The Boot#### option which will be invoked if this key is pressed and the boot option"]
#[doc = " is active (LOAD_OPTION_ACTIVE is set)."]
#[doc = ""]
pub BootOption: UINT16,
}
#[test]
fn bindgen_test_layout_EFI_KEY_OPTION() {
assert_eq!(
::std::mem::size_of::<EFI_KEY_OPTION>(),
10usize,
concat!("Size of: ", stringify!(EFI_KEY_OPTION))
);
assert_eq!(
::std::mem::align_of::<EFI_KEY_OPTION>(),
1usize,
concat!("Alignment of ", stringify!(EFI_KEY_OPTION))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<EFI_KEY_OPTION>())).KeyData as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(EFI_KEY_OPTION),
"::",
stringify!(KeyData)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<EFI_KEY_OPTION>())).BootOptionCrc as *const _ as usize },
4usize,
concat!(
"Offset of field: ",
stringify!(EFI_KEY_OPTION),
"::",
stringify!(BootOptionCrc)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<EFI_KEY_OPTION>())).BootOption as *const _ as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(EFI_KEY_OPTION),
"::",
stringify!(BootOption)
)
);
}
Expected Results
Build correctly
Activity