diff options
Diffstat (limited to 'src/codegen/mod.rs')
-rw-r--r-- | src/codegen/mod.rs | 153 |
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 |