diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 67d6b6d576..1bff1e263b 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -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 { @@ -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 diff --git a/tests/expectations/tests/union-align.rs b/tests/expectations/tests/union-align.rs new file mode 100644 index 0000000000..01eb78b7f9 --- /dev/null +++ b/tests/expectations/tests/union-align.rs @@ -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::(), + 16usize, + concat!("Size of: ", stringify!(Bar)) + ); + assert_eq!( + ::std::mem::align_of::(), + 16usize, + concat!("Alignment of ", stringify!(Bar)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).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() } + } +} diff --git a/tests/headers/long_double.h b/tests/headers/long_double.h new file mode 100644 index 0000000000..91c4ed6ce9 --- /dev/null +++ b/tests/headers/long_double.h @@ -0,0 +1,5 @@ +// bindgen-flags: --rust-target 1.26 + +struct foo { + long double bar; +}; diff --git a/tests/headers/union-align.h b/tests/headers/union-align.h new file mode 100644 index 0000000000..94e60ef165 --- /dev/null +++ b/tests/headers/union-align.h @@ -0,0 +1,5 @@ +// bindgen-flags: --rust-target 1.26 + +union Bar { + unsigned char foo; +} __attribute__ ((__aligned__ (16)));