Skip to content

Commit

Permalink
codegen: Explicitly align unions if needed.
Browse files Browse the repository at this point in the history
Also adds a test header I missed from the previous PR.

Fixes #1393
  • Loading branch information
emilio committed Sep 21, 2018
1 parent 6fc0a31 commit dcb9921
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 21 deletions.
47 changes: 26 additions & 21 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1540,27 +1540,6 @@ impl CodeGenerator for CompInfo {

let is_union = self.kind() == CompKind::Union;
let layout = item.kind().expect_type().layout(ctx);
if is_union && !is_opaque && !self.is_forward_declaration() {
result.saw_union();
if !self.can_be_rust_union(ctx) {
result.saw_bindgen_union();
}

let layout = layout.expect("Unable to get layout information?");
let ty = helpers::blob(ctx, layout);

fields.push(if self.can_be_rust_union(ctx) {
quote! {
_bindgen_union_align: #ty ,
}
} else {
struct_layout.saw_union(layout);

quote! {
pub bindgen_union_field: #ty ,
}
});
}

let mut explicit_align = None;
if is_opaque {
Expand Down Expand Up @@ -1603,6 +1582,32 @@ impl CodeGenerator for CompInfo {
}
}
}
} else if is_union && !self.is_forward_declaration() {
result.saw_union();
if !self.can_be_rust_union(ctx) {
result.saw_bindgen_union();
}

// TODO(emilio): It'd be nice to unify this with the struct path
// above somehow.
let layout = layout.expect("Unable to get layout information?");

if struct_layout.requires_explicit_align(layout) {
explicit_align = Some(layout.align);
}

let ty = helpers::blob(ctx, layout);
fields.push(if self.can_be_rust_union(ctx) {
quote! {
_bindgen_union_align: #ty ,
}
} else {
struct_layout.saw_union(layout);

quote! {
pub bindgen_union_field: #ty ,
}
});
}

// C++ requires every struct to be addressable, so what C++ compilers do
Expand Down
39 changes: 39 additions & 0 deletions tests/expectations/tests/union-align.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* automatically generated by rust-bindgen */

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

#[repr(C)]
#[repr(align(16))]
#[derive(Copy, Clone)]
pub union Bar {
pub foo: ::std::os::raw::c_uchar,
_bindgen_union_align: u128,
}
#[test]
fn bindgen_test_layout_Bar() {
assert_eq!(
::std::mem::size_of::<Bar>(),
16usize,
concat!("Size of: ", stringify!(Bar))
);
assert_eq!(
::std::mem::align_of::<Bar>(),
16usize,
concat!("Alignment of ", stringify!(Bar))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Bar>())).foo as *const _ as usize },
0usize,
concat!("Offset of field: ", stringify!(Bar), "::", stringify!(foo))
);
}
impl Default for Bar {
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
}
}
5 changes: 5 additions & 0 deletions tests/headers/long_double.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// bindgen-flags: --rust-target 1.26

struct foo {
long double bar;
};
5 changes: 5 additions & 0 deletions tests/headers/union-align.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// bindgen-flags: --rust-target 1.26

union Bar {
unsigned char foo;
} __attribute__ ((__aligned__ (16)));

0 comments on commit dcb9921

Please sign in to comment.