summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/codegen/mod.rs153
-rw-r--r--src/lib.rs59
-rw-r--r--src/options.rs61
-rw-r--r--tests/expectations/tests/union_with_non_copy_member.rs239
-rw-r--r--tests/headers/union_with_non_copy_member.h20
5 files changed, 499 insertions, 33 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index f1422d6b..98ab922a 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -1231,7 +1231,7 @@ trait FieldCodegen<'a> {
}
impl<'a> FieldCodegen<'a> for Field {
- type Extra = ();
+ type Extra = &'a str;
fn codegen<F, M>(
&self,
@@ -1244,7 +1244,7 @@ impl<'a> FieldCodegen<'a> for Field {
struct_layout: &mut StructLayoutTracker,
fields: &mut F,
methods: &mut M,
- _: (),
+ parent_canonical_name: Self::Extra,
) where
F: Extend<proc_macro2::TokenStream>,
M: Extend<proc_macro2::TokenStream>,
@@ -1261,7 +1261,7 @@ impl<'a> FieldCodegen<'a> for Field {
struct_layout,
fields,
methods,
- (),
+ parent_canonical_name,
);
}
Field::Bitfields(ref unit) => {
@@ -1275,7 +1275,7 @@ impl<'a> FieldCodegen<'a> for Field {
struct_layout,
fields,
methods,
- (),
+ parent_canonical_name,
);
}
}
@@ -1283,7 +1283,7 @@ impl<'a> FieldCodegen<'a> for Field {
}
impl<'a> FieldCodegen<'a> for FieldData {
- type Extra = ();
+ type Extra = &'a str;
fn codegen<F, M>(
&self,
@@ -1296,7 +1296,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
struct_layout: &mut StructLayoutTracker,
fields: &mut F,
methods: &mut M,
- _: (),
+ parent_canonical_name: Self::Extra,
) where
F: Extend<proc_macro2::TokenStream>,
M: Extend<proc_macro2::TokenStream>,
@@ -1313,16 +1313,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
// NB: If supported, we use proper `union` types.
let ty = if parent.is_union() && !struct_layout.is_rust_union() {
- result.saw_bindgen_union();
- if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__BindgenUnionField<#ty>
- }
- } else {
- quote! {
- __BindgenUnionField<#ty>
- }
- }
+ wrap_non_copy_type_for_union(ctx, parent_canonical_name, result, ty)
} else if let Some(item) = field_ty.is_incomplete_array(ctx) {
result.saw_incomplete_array();
@@ -1433,6 +1424,54 @@ impl<'a> FieldCodegen<'a> for FieldData {
}
}
+fn wrap_non_copy_type_for_union(
+ ctx: &BindgenContext,
+ parent_canonical_name: &str,
+ result: &mut CodegenResult,
+ field_ty: proc_macro2::TokenStream,
+) -> proc_macro2::TokenStream {
+ let union_style = union_style_from_ctx_and_name(ctx, parent_canonical_name);
+
+ match union_style {
+ NonCopyUnionStyle::ManuallyDrop => {
+ if ctx.options().use_core {
+ quote! {
+ ::core::mem::ManuallyDrop<#field_ty>
+ }
+ } else {
+ quote! {
+ ::std::mem::ManuallyDrop<#field_ty>
+ }
+ }
+ }
+ NonCopyUnionStyle::BindgenWrapper => {
+ result.saw_bindgen_union();
+ if ctx.options().enable_cxx_namespaces {
+ quote! {
+ root::__BindgenUnionField<#field_ty>
+ }
+ } else {
+ quote! {
+ __BindgenUnionField<#field_ty>
+ }
+ }
+ }
+ }
+}
+
+fn union_style_from_ctx_and_name(
+ ctx: &BindgenContext,
+ canonical_name: &str,
+) -> NonCopyUnionStyle {
+ if ctx.options().bindgen_wrapper_union.matches(canonical_name) {
+ NonCopyUnionStyle::BindgenWrapper
+ } else if ctx.options().manually_drop_union.matches(canonical_name) {
+ NonCopyUnionStyle::ManuallyDrop
+ } else {
+ ctx.options().default_non_copy_union_style
+ }
+}
+
impl BitfieldUnit {
/// Get the constructor name for this bitfield unit.
fn ctor_name(&self) -> proc_macro2::TokenStream {
@@ -1499,7 +1538,7 @@ fn access_specifier(
}
impl<'a> FieldCodegen<'a> for BitfieldUnit {
- type Extra = ();
+ type Extra = &'a str;
fn codegen<F, M>(
&self,
@@ -1512,7 +1551,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
struct_layout: &mut StructLayoutTracker,
fields: &mut F,
methods: &mut M,
- _: (),
+ parent_canonical_name: Self::Extra,
) where
F: Extend<proc_macro2::TokenStream>,
M: Extend<proc_macro2::TokenStream>,
@@ -1525,16 +1564,12 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
let unit_field_ty = helpers::bitfield_unit(ctx, layout);
let field_ty = {
if parent.is_union() && !struct_layout.is_rust_union() {
- result.saw_bindgen_union();
- if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__BindgenUnionField<#unit_field_ty>
- }
- } else {
- quote! {
- __BindgenUnionField<#unit_field_ty>
- }
- }
+ wrap_non_copy_type_for_union(
+ ctx,
+ parent_canonical_name,
+ result,
+ unit_field_ty.clone(),
+ )
} else {
unit_field_ty.clone()
}
@@ -1859,7 +1894,7 @@ impl CodeGenerator for CompInfo {
&mut struct_layout,
&mut fields,
&mut methods,
- (),
+ &canonical_name,
);
}
// Check whether an explicit padding field is needed
@@ -1965,7 +2000,10 @@ impl CodeGenerator for CompInfo {
explicit_align = Some(layout.align);
}
- if !struct_layout.is_rust_union() {
+ if !struct_layout.is_rust_union() &&
+ union_style_from_ctx_and_name(ctx, &canonical_name) ==
+ NonCopyUnionStyle::BindgenWrapper
+ {
let ty = helpers::blob(ctx, layout);
fields.push(quote! {
pub bindgen_union_field: #ty ,
@@ -2092,6 +2130,15 @@ impl CodeGenerator for CompInfo {
#( #attributes )*
pub union #canonical_ident
}
+ } else if is_union &&
+ !struct_layout.is_rust_union() &&
+ union_style_from_ctx_and_name(ctx, &canonical_name) ==
+ NonCopyUnionStyle::ManuallyDrop
+ {
+ quote! {
+ #( #attributes )*
+ pub union #canonical_ident
+ }
} else {
quote! {
#( #attributes )*
@@ -3398,6 +3445,52 @@ impl std::str::FromStr for AliasVariation {
}
}
+/// Enum for how non-Copy unions should be translated.
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum NonCopyUnionStyle {
+ /// Wrap members in a type generated by bindgen.
+ BindgenWrapper,
+ /// Wrap members in [`::core::mem::ManuallyDrop`].
+ ///
+ /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your
+ /// MSRV is lower.
+ ManuallyDrop,
+}
+
+impl NonCopyUnionStyle {
+ /// Convert an `NonCopyUnionStyle` to its str representation.
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ Self::BindgenWrapper => "bindgen_wrapper",
+ Self::ManuallyDrop => "manually_drop",
+ }
+ }
+}
+
+impl Default for NonCopyUnionStyle {
+ fn default() -> Self {
+ Self::BindgenWrapper
+ }
+}
+
+impl std::str::FromStr for NonCopyUnionStyle {
+ type Err = std::io::Error;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "bindgen_wrapper" => Ok(Self::BindgenWrapper),
+ "manually_drop" => Ok(Self::ManuallyDrop),
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidInput,
+ concat!(
+ "Got an invalid NonCopyUnionStyle. Accepted values ",
+ "are 'bindgen_wrapper' and 'manually_drop'"
+ ),
+ )),
+ }
+ }
+}
+
/// Fallible conversion to an opaque blob.
///
/// Implementors of this trait should provide the `try_get_layout` method to
diff --git a/src/lib.rs b/src/lib.rs
index 8c41565a..c7fccb98 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -66,7 +66,9 @@ doc_mod!(ir, ir_docs);
doc_mod!(parse, parse_docs);
doc_mod!(regex_set, regex_set_docs);
-pub use crate::codegen::{AliasVariation, EnumVariation, MacroTypeVariation};
+pub use crate::codegen::{
+ AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle,
+};
use crate::features::RustFeatures;
pub use crate::features::{
RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS,
@@ -312,6 +314,13 @@ impl Builder {
.push(self.options.default_alias_style.as_str().into());
}
+ if self.options.default_non_copy_union_style != Default::default() {
+ output_vector.push("--default-non-copy-union-style".into());
+ output_vector.push(
+ self.options.default_non_copy_union_style.as_str().into(),
+ );
+ }
+
let regex_sets = &[
(&self.options.bitfield_enums, "--bitfield-enum"),
(&self.options.newtype_enums, "--newtype-enum"),
@@ -329,6 +338,11 @@ impl Builder {
(&self.options.type_alias, "--type-alias"),
(&self.options.new_type_alias, "--new-type-alias"),
(&self.options.new_type_alias_deref, "--new-type-alias-deref"),
+ (
+ &self.options.bindgen_wrapper_union,
+ "--bindgen-wrapper-union",
+ ),
+ (&self.options.manually_drop_union, "--manually-drop-union"),
(&self.options.blocklisted_types, "--blocklist-type"),
(&self.options.blocklisted_functions, "--blocklist-function"),
(&self.options.blocklisted_items, "--blocklist-item"),
@@ -1101,6 +1115,32 @@ impl Builder {
self
}
+ /// Set the default style of code to generate for unions with a non-Copy member.
+ pub fn default_non_copy_union_style(
+ mut self,
+ arg: codegen::NonCopyUnionStyle,
+ ) -> Self {
+ self.options.default_non_copy_union_style = arg;
+ self
+ }
+
+ /// Mark the given union (or set of union, if using a pattern) to use
+ /// a bindgen-generated wrapper for its members if at least one is non-Copy.
+ pub fn bindgen_wrapper_union<T: AsRef<str>>(mut self, arg: T) -> Self {
+ self.options.bindgen_wrapper_union.insert(arg);
+ self
+ }
+
+ /// Mark the given union (or set of union, if using a pattern) to use
+ /// [`::core::mem::ManuallyDrop`] for its members if at least one is non-Copy.
+ ///
+ /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your
+ /// MSRV is lower.
+ pub fn manually_drop_union<T: AsRef<str>>(mut self, arg: T) -> Self {
+ self.options.manually_drop_union.insert(arg);
+ self
+ }
+
/// Add a string to prepend to the generated bindings. The string is passed
/// through without any modification.
pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self {
@@ -1811,6 +1851,18 @@ struct BindgenOptions {
/// Deref and Deref to their aliased type.
new_type_alias_deref: RegexSet,
+ /// The default style of code to generate for union containing non-Copy
+ /// members.
+ default_non_copy_union_style: codegen::NonCopyUnionStyle,
+
+ /// The union patterns to mark an non-Copy union as using the bindgen
+ /// generated wrapper.
+ bindgen_wrapper_union: RegexSet,
+
+ /// The union patterns to mark an non-Copy union as using the
+ /// `::core::mem::ManuallyDrop` wrapper.
+ manually_drop_union: RegexSet,
+
/// Whether we should generate builtins or not.
builtins: bool,
@@ -2079,6 +2131,8 @@ impl BindgenOptions {
&mut self.type_alias,
&mut self.new_type_alias,
&mut self.new_type_alias_deref,
+ &mut self.bindgen_wrapper_union,
+ &mut self.manually_drop_union,
&mut self.no_partialeq_types,
&mut self.no_copy_types,
&mut self.no_debug_types,
@@ -2137,6 +2191,9 @@ impl Default for BindgenOptions {
type_alias: Default::default(),
new_type_alias: Default::default(),
new_type_alias_deref: Default::default(),
+ default_non_copy_union_style: Default::default(),
+ bindgen_wrapper_union: Default::default(),
+ manually_drop_union: Default::default(),
builtins: false,
emit_ast: false,
emit_ir: false,
diff --git a/src/options.rs b/src/options.rs
index 4db3fd57..1e87b6eb 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -1,7 +1,7 @@
use bindgen::{
builder, AliasVariation, Builder, CodegenConfig, EnumVariation,
- MacroTypeVariation, RustTarget, DEFAULT_ANON_FIELDS_PREFIX,
- RUST_TARGET_STRINGS,
+ MacroTypeVariation, NonCopyUnionStyle, RustTarget,
+ DEFAULT_ANON_FIELDS_PREFIX, RUST_TARGET_STRINGS,
};
use clap::{App, Arg};
use std::fs::File;
@@ -138,6 +138,42 @@ where
.value_name("regex")
.multiple_occurrences(true)
.number_of_values(1),
+ Arg::new("default-non-copy-union-style")
+ .long("default-non-copy-union-style")
+ .help(
+ "The default style of code used to generate unions with \
+ non-Copy members. Note that ManuallyDrop was first \
+ stabilized in Rust 1.20.0.",
+ )
+ .value_name("style")
+ .default_value("bindgen_wrapper")
+ .possible_values(&[
+ "bindgen_wrapper",
+ "manually_drop",
+ ])
+ .multiple_occurrences(false),
+ Arg::new("bindgen-wrapper-union")
+ .long("bindgen-wrapper-union")
+ .help(
+ "Mark any union whose name matches <regex> and who has a \
+ non-Copy member to use a bindgen-generated wrapper for \
+ fields.",
+ )
+ .value_name("regex")
+ .takes_value(true)
+ .multiple_occurrences(true)
+ .number_of_values(1),
+ Arg::new("manually-drop-union")
+ .long("manually-drop-union")
+ .help(
+ "Mark any union whose name matches <regex> and who has a \
+ non-Copy member to use ManuallyDrop (stabilized in Rust \
+ 1.20.0) for fields.",
+ )
+ .value_name("regex")
+ .takes_value(true)
+ .multiple_occurrences(true)
+ .number_of_values(1),
Arg::new("blocklist-type")
.alias("blacklist-type")
.long("blocklist-type")
@@ -631,6 +667,27 @@ where
}
}
+ if let Some(variant) = matches.value_of("default-non-copy-union-style") {
+ builder = builder.default_non_copy_union_style(
+ NonCopyUnionStyle::from_str(variant)?,
+ );
+ }
+
+ if let Some(bindgen_wrapper_union) =
+ matches.values_of("bindgen-wrapper-union")
+ {
+ for regex in bindgen_wrapper_union {
+ builder = builder.bindgen_wrapper_union(regex);
+ }
+ }
+
+ if let Some(manually_drop_union) = matches.values_of("manually-drop-union")
+ {
+ for regex in manually_drop_union {
+ builder = builder.manually_drop_union(regex);
+ }
+ }
+
if let Some(hidden_types) = matches.values_of("blocklist-type") {
for ty in hidden_types {
builder = builder.blocklist_type(ty);
diff --git a/tests/expectations/tests/union_with_non_copy_member.rs b/tests/expectations/tests/union_with_non_copy_member.rs
new file mode 100644
index 00000000..3c500b21
--- /dev/null
+++ b/tests/expectations/tests/union_with_non_copy_member.rs
@@ -0,0 +1,239 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
+impl<T> __BindgenUnionField<T> {
+ #[inline]
+ pub const fn new() -> Self {
+ __BindgenUnionField(::std::marker::PhantomData)
+ }
+ #[inline]
+ pub unsafe fn as_ref(&self) -> &T {
+ ::std::mem::transmute(self)
+ }
+ #[inline]
+ pub unsafe fn as_mut(&mut self) -> &mut T {
+ ::std::mem::transmute(self)
+ }
+}
+impl<T> ::std::default::Default for __BindgenUnionField<T> {
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+}
+impl<T> ::std::clone::Clone for __BindgenUnionField<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ Self::new()
+ }
+}
+impl<T> ::std::marker::Copy for __BindgenUnionField<T> {}
+impl<T> ::std::fmt::Debug for __BindgenUnionField<T> {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ fmt.write_str("__BindgenUnionField")
+ }
+}
+impl<T> ::std::hash::Hash for __BindgenUnionField<T> {
+ fn hash<H: ::std::hash::Hasher>(&self, _state: &mut H) {}
+}
+impl<T> ::std::cmp::PartialEq for __BindgenUnionField<T> {
+ fn eq(&self, _other: &__BindgenUnionField<T>) -> bool {
+ true
+ }
+}
+impl<T> ::std::cmp::Eq for __BindgenUnionField<T> {}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct NonCopyType {
+ pub foo: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_NonCopyType() {
+ const UNINIT: ::std::mem::MaybeUninit<NonCopyType> =
+ ::std::mem::MaybeUninit::uninit();
+ let ptr = UNINIT.as_ptr();
+ assert_eq!(
+ ::std::mem::size_of::<NonCopyType>(),
+ 4usize,
+ concat!("Size of: ", stringify!(NonCopyType))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<NonCopyType>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(NonCopyType))
+ );
+ assert_eq!(
+ unsafe { ::std::ptr::addr_of!((*ptr).foo) as usize - ptr as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(NonCopyType),
+ "::",
+ stringify!(foo)
+ )
+ );
+}
+#[repr(C)]
+pub struct WithBindgenGeneratedWrapper {
+ pub non_copy_type: __BindgenUnionField<NonCopyType>,
+ pub bar: __BindgenUnionField<::std::os::raw::c_int>,
+ pub bindgen_union_field: u32,
+}
+#[test]
+fn bindgen_test_layout_WithBindgenGeneratedWrapper() {
+ const UNINIT: ::std::mem::MaybeUninit<WithBindgenGeneratedWrapper> =
+ ::std::mem::MaybeUninit::uninit();
+ let ptr = UNINIT.as_ptr();
+ assert_eq!(
+ ::std::mem::size_of::<WithBindgenGeneratedWrapper>(),
+ 4usize,
+ concat!("Size of: ", stringify!(WithBindgenGeneratedWrapper))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<WithBindgenGeneratedWrapper>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(WithBindgenGeneratedWrapper))
+ );
+ assert_eq!(
+ unsafe {
+ ::std::ptr::addr_of!((*ptr).non_copy_type) as usize - ptr as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(WithBindgenGeneratedWrapper),
+ "::",
+ stringify!(non_copy_type)
+ )
+ );
+ assert_eq!(
+ unsafe { ::std::ptr::addr_of!((*ptr).bar) as usize - ptr as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(WithBindgenGeneratedWrapper),
+ "::",
+ stringify!(bar)
+ )
+ );
+}
+impl Default for WithBindgenGeneratedWrapper {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+pub union WithManuallyDrop {
+ pub non_copy_type: ::std::mem::ManuallyDrop<NonCopyType>,
+ pub bar: ::std::mem::ManuallyDrop<::std::os::raw::c_int>,
+}
+#[test]
+fn bindgen_test_layout_WithManuallyDrop() {
+ const UNINIT: ::std::mem::MaybeUninit<WithManuallyDrop> =
+ ::std::mem::MaybeUninit::uninit();
+ let ptr = UNINIT.as_ptr();
+ assert_eq!(
+ ::std::mem::size_of::<WithManuallyDrop>(),
+ 4usize,
+ concat!("Size of: ", stringify!(WithManuallyDrop))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<WithManuallyDrop>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(WithManuallyDrop))
+ );
+ assert_eq!(
+ unsafe {
+ ::std::ptr::addr_of!((*ptr).non_copy_type) as usize - ptr as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(WithManuallyDrop),
+ "::",
+ stringify!(non_copy_type)
+ )
+ );
+ assert_eq!(
+ unsafe { ::std::ptr::addr_of!((*ptr).bar) as usize - ptr as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(WithManuallyDrop),
+ "::",
+ stringify!(bar)
+ )
+ );
+}
+impl Default for WithManuallyDrop {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+pub struct WithDefaultWrapper {
+ pub non_copy_type: __BindgenUnionField<NonCopyType>,
+ pub bar: __BindgenUnionField<::std::os::raw::c_int>,
+ pub bindgen_union_field: u32,
+}
+#[test]
+fn bindgen_test_layout_WithDefaultWrapper() {
+ const UNINIT: ::std::mem::MaybeUninit<WithDefaultWrapper> =
+ ::std::mem::MaybeUninit::uninit();
+ let ptr = UNINIT.as_ptr();
+ assert_eq!(
+ ::std::mem::size_of::<WithDefaultWrapper>(),
+ 4usize,
+ concat!("Size of: ", stringify!(WithDefaultWrapper))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<WithDefaultWrapper>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(WithDefaultWrapper))
+ );
+ assert_eq!(
+ unsafe {
+ ::std::ptr::addr_of!((*ptr).non_copy_type) as usize - ptr as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(WithDefaultWrapper),
+ "::",
+ stringify!(non_copy_type)
+ )
+ );
+ assert_eq!(
+ unsafe { ::std::ptr::addr_of!((*ptr).bar) as usize - ptr as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(WithDefaultWrapper),
+ "::",
+ stringify!(bar)
+ )
+ );
+}
+impl Default for WithDefaultWrapper {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
diff --git a/tests/headers/union_with_non_copy_member.h b/tests/headers/union_with_non_copy_member.h
new file mode 100644
index 00000000..764820a4
--- /dev/null
+++ b/tests/headers/union_with_non_copy_member.h
@@ -0,0 +1,20 @@
+// bindgen-flags: --bindgen-wrapper-union 'WithBindgenGeneratedWrapper' --manually-drop-union 'WithManuallyDrop' --no-copy 'NonCopyType'
+
+struct NonCopyType {
+ int foo;
+};
+
+union WithBindgenGeneratedWrapper {
+ struct NonCopyType non_copy_type;
+ int bar;
+};
+
+union WithManuallyDrop {
+ struct NonCopyType non_copy_type;
+ int bar;
+};
+
+union WithDefaultWrapper {
+ struct NonCopyType non_copy_type;
+ int bar;
+};