Skip to content
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

ir: Properly find the layout of incomplete arrays. #1592

Merged
merged 1 commit into from Jul 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/ir/ty.rs
Expand Up @@ -249,6 +249,12 @@ impl Type {
self.layout.or_else(|| {
match self.kind {
TypeKind::Comp(ref ci) => ci.layout(ctx),
TypeKind::Array(inner, length) if length == 0 => {
Some(Layout::new(
0,
ctx.resolve_type(inner).layout(ctx)?.align,
))
}
// FIXME(emilio): This is a hack for anonymous union templates.
// Use the actual pointer size!
TypeKind::Pointer(..) => {
Expand Down
173 changes: 173 additions & 0 deletions tests/expectations/tests/incomplete-array-padding.rs
@@ -0,0 +1,173 @@
/* automatically generated by rust-bindgen */

#![allow(
dead_code,
non_snake_case,
non_camel_case_types,
non_upper_case_globals
)]

#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct __BindgenBitfieldUnit<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(Default)]
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
impl<T> __IncompleteArrayField<T> {
#[inline]
pub const fn new() -> Self {
__IncompleteArrayField(::std::marker::PhantomData, [])
}
#[inline]
pub unsafe fn as_ptr(&self) -> *const T {
::std::mem::transmute(self)
}
#[inline]
pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
::std::mem::transmute(self)
}
#[inline]
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
::std::slice::from_raw_parts(self.as_ptr(), len)
}
#[inline]
pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
}
}
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_str("__IncompleteArrayField")
}
}
impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
#[inline]
fn clone(&self) -> Self {
Self::new()
}
}
#[repr(C)]
#[derive(Debug)]
pub struct foo {
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize], u8>,
pub b: __IncompleteArrayField<*mut ::std::os::raw::c_void>,
}
#[test]
fn bindgen_test_layout_foo() {
assert_eq!(
::std::mem::size_of::<foo>(),
8usize,
concat!("Size of: ", stringify!(foo))
);
assert_eq!(
::std::mem::align_of::<foo>(),
8usize,
concat!("Alignment of ", stringify!(foo))
);
}
impl Default for foo {
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
}
}
impl foo {
#[inline]
pub fn a(&self) -> ::std::os::raw::c_char {
unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u8) }
}
#[inline]
pub fn set_a(&mut self, val: ::std::os::raw::c_char) {
unsafe {
let val: u8 = ::std::mem::transmute(val);
self._bitfield_1.set(0usize, 1u8, val as u64)
}
}
#[inline]
pub fn new_bitfield_1(a: ::std::os::raw::c_char) -> __BindgenBitfieldUnit<[u8; 1usize], u8> {
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize], u8> =
Default::default();
__bindgen_bitfield_unit.set(0usize, 1u8, {
let a: u8 = unsafe { ::std::mem::transmute(a) };
a as u64
});
__bindgen_bitfield_unit
}
}
1 change: 0 additions & 1 deletion tests/expectations/tests/layout_align.rs
Expand Up @@ -125,7 +125,6 @@ impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
}
}
#[repr(C)]
#[repr(align(8))]
#[derive(Debug)]
pub struct rte_kni_fifo {
///< Next position to be written
Expand Down
2 changes: 1 addition & 1 deletion tests/expectations/tests/zero-sized-array.rs
Expand Up @@ -122,7 +122,7 @@ fn bindgen_test_layout_InheritsZeroSizedArray() {
);
}
/// And this should not get an `_address` field either.
#[repr(C, packed)]
#[repr(C)]
#[derive(Debug, Default)]
pub struct DynamicallySizedArray {
pub arr: __IncompleteArrayField<::std::os::raw::c_char>,
Expand Down
4 changes: 4 additions & 0 deletions tests/headers/incomplete-array-padding.h
@@ -0,0 +1,4 @@
struct foo {
char a : 1;
void *b[];
};