Skip to content

Commit dcb9921

Browse files
committed
codegen: Explicitly align unions if needed.
Also adds a test header I missed from the previous PR. Fixes #1393
1 parent 6fc0a31 commit dcb9921

File tree

4 files changed

+75
-21
lines changed

4 files changed

+75
-21
lines changed

src/codegen/mod.rs

+26-21
Original file line numberDiff line numberDiff line change
@@ -1540,27 +1540,6 @@ impl CodeGenerator for CompInfo {
15401540

15411541
let is_union = self.kind() == CompKind::Union;
15421542
let layout = item.kind().expect_type().layout(ctx);
1543-
if is_union && !is_opaque && !self.is_forward_declaration() {
1544-
result.saw_union();
1545-
if !self.can_be_rust_union(ctx) {
1546-
result.saw_bindgen_union();
1547-
}
1548-
1549-
let layout = layout.expect("Unable to get layout information?");
1550-
let ty = helpers::blob(ctx, layout);
1551-
1552-
fields.push(if self.can_be_rust_union(ctx) {
1553-
quote! {
1554-
_bindgen_union_align: #ty ,
1555-
}
1556-
} else {
1557-
struct_layout.saw_union(layout);
1558-
1559-
quote! {
1560-
pub bindgen_union_field: #ty ,
1561-
}
1562-
});
1563-
}
15641543

15651544
let mut explicit_align = None;
15661545
if is_opaque {
@@ -1603,6 +1582,32 @@ impl CodeGenerator for CompInfo {
16031582
}
16041583
}
16051584
}
1585+
} else if is_union && !self.is_forward_declaration() {
1586+
result.saw_union();
1587+
if !self.can_be_rust_union(ctx) {
1588+
result.saw_bindgen_union();
1589+
}
1590+
1591+
// TODO(emilio): It'd be nice to unify this with the struct path
1592+
// above somehow.
1593+
let layout = layout.expect("Unable to get layout information?");
1594+
1595+
if struct_layout.requires_explicit_align(layout) {
1596+
explicit_align = Some(layout.align);
1597+
}
1598+
1599+
let ty = helpers::blob(ctx, layout);
1600+
fields.push(if self.can_be_rust_union(ctx) {
1601+
quote! {
1602+
_bindgen_union_align: #ty ,
1603+
}
1604+
} else {
1605+
struct_layout.saw_union(layout);
1606+
1607+
quote! {
1608+
pub bindgen_union_field: #ty ,
1609+
}
1610+
});
16061611
}
16071612

16081613
// C++ requires every struct to be addressable, so what C++ compilers do
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
9+
10+
#[repr(C)]
11+
#[repr(align(16))]
12+
#[derive(Copy, Clone)]
13+
pub union Bar {
14+
pub foo: ::std::os::raw::c_uchar,
15+
_bindgen_union_align: u128,
16+
}
17+
#[test]
18+
fn bindgen_test_layout_Bar() {
19+
assert_eq!(
20+
::std::mem::size_of::<Bar>(),
21+
16usize,
22+
concat!("Size of: ", stringify!(Bar))
23+
);
24+
assert_eq!(
25+
::std::mem::align_of::<Bar>(),
26+
16usize,
27+
concat!("Alignment of ", stringify!(Bar))
28+
);
29+
assert_eq!(
30+
unsafe { &(*(::std::ptr::null::<Bar>())).foo as *const _ as usize },
31+
0usize,
32+
concat!("Offset of field: ", stringify!(Bar), "::", stringify!(foo))
33+
);
34+
}
35+
impl Default for Bar {
36+
fn default() -> Self {
37+
unsafe { ::std::mem::zeroed() }
38+
}
39+
}

tests/headers/long_double.h

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// bindgen-flags: --rust-target 1.26
2+
3+
struct foo {
4+
long double bar;
5+
};

tests/headers/union-align.h

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// bindgen-flags: --rust-target 1.26
2+
3+
union Bar {
4+
unsigned char foo;
5+
} __attribute__ ((__aligned__ (16)));

0 commit comments

Comments
 (0)