Skip to content

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

Open
himself65 opened this issue Oct 1, 2020 · 6 comments
Open

Comments

@himself65
Copy link

himself65 commented 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

@himself65
Copy link
Author

It seems that runs error when packed struct has a union data

@himself65
Copy link
Author

himself65 commented Oct 1, 2020

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.

@himself65
Copy link
Author

in Line 91

#[repr(align(4))]

@Masterchef365
Copy link

Masterchef365 commented Oct 2, 2020

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

@emilio
Copy link
Contributor

emilio commented Nov 13, 2020

So... generally this is kind of a rust bug, but in this case bindgen could avoid generating the repr(align) by using an u32 for the bitfield.

I'll update the OP with the minimized test-case. Thanks @himself65!

@emilio
Copy link
Contributor

emilio commented Nov 13, 2020

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:

struct Foo {
  int a:2;
};

is this:

pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize], u8>,

This is correct in the general case (because if you stash a char after the bitfield it shouldn't grow).

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 repr(align).

The relevant code is raw_fields_to_fields_and_bitfield_units in src/ir/comp.rs, and you'd need to propagate whether you're the last field down to flush_allocation_unit, where you could bump the alignment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants