summaryrefslogtreecommitdiff
path: root/src/codegen/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/mod.rs')
-rw-r--r--src/codegen/mod.rs153
1 files changed, 123 insertions, 30 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