diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/codegen/mod.rs | 133 | ||||
-rw-r--r-- | src/codegen/struct_layout.rs | 10 | ||||
-rw-r--r-- | src/ir/comp.rs | 35 |
3 files changed, 84 insertions, 94 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 98ab922a..843d5111 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 = &'a str; + type Extra = (); 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,15 +1275,44 @@ impl<'a> FieldCodegen<'a> for Field { struct_layout, fields, methods, - parent_canonical_name, + (), ); } } } } +fn wrap_union_field_if_needed( + ctx: &BindgenContext, + struct_layout: &StructLayoutTracker, + ty: proc_macro2::TokenStream, + result: &mut CodegenResult, +) -> proc_macro2::TokenStream { + if struct_layout.is_rust_union() { + if struct_layout.can_copy_union_fields() { + ty + } else { + let prefix = ctx.trait_prefix(); + quote! { + ::#prefix::mem::ManuallyDrop<#ty> + } + } + } else { + result.saw_bindgen_union(); + if ctx.options().enable_cxx_namespaces { + quote! { + root::__BindgenUnionField<#ty> + } + } else { + quote! { + __BindgenUnionField<#ty> + } + } + } +} + impl<'a> FieldCodegen<'a> for FieldData { - type Extra = &'a str; + type Extra = (); fn codegen<F, M>( &self, @@ -1296,7 +1325,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>, @@ -1312,8 +1341,8 @@ impl<'a> FieldCodegen<'a> for FieldData { ty.append_implicit_template_params(ctx, field_item); // NB: If supported, we use proper `union` types. - let ty = if parent.is_union() && !struct_layout.is_rust_union() { - wrap_non_copy_type_for_union(ctx, parent_canonical_name, result, ty) + let ty = if parent.is_union() { + wrap_union_field_if_needed(ctx, struct_layout, ty, result) } else if let Some(item) = field_ty.is_incomplete_array(ctx) { result.saw_incomplete_array(); @@ -1424,54 +1453,6 @@ 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 { @@ -1538,7 +1519,7 @@ fn access_specifier( } impl<'a> FieldCodegen<'a> for BitfieldUnit { - type Extra = &'a str; + type Extra = (); fn codegen<F, M>( &self, @@ -1551,7 +1532,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>, @@ -1562,17 +1543,15 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { let layout = self.layout(); let unit_field_ty = helpers::bitfield_unit(ctx, layout); - let field_ty = { - if parent.is_union() && !struct_layout.is_rust_union() { - wrap_non_copy_type_for_union( - ctx, - parent_canonical_name, - result, - unit_field_ty.clone(), - ) - } else { - unit_field_ty.clone() - } + let field_ty = if parent.is_union() { + wrap_union_field_if_needed( + ctx, + struct_layout, + unit_field_ty.clone(), + result, + ) + } else { + unit_field_ty.clone() }; { @@ -1894,7 +1873,7 @@ impl CodeGenerator for CompInfo { &mut struct_layout, &mut fields, &mut methods, - &canonical_name, + (), ); } // Check whether an explicit padding field is needed @@ -2000,10 +1979,7 @@ impl CodeGenerator for CompInfo { explicit_align = Some(layout.align); } - if !struct_layout.is_rust_union() && - union_style_from_ctx_and_name(ctx, &canonical_name) == - NonCopyUnionStyle::BindgenWrapper - { + if !struct_layout.is_rust_union() { let ty = helpers::blob(ctx, layout); fields.push(quote! { pub bindgen_union_field: #ty , @@ -2130,15 +2106,6 @@ 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 )* diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs index 657be0b4..ddac1b0a 100644 --- a/src/codegen/struct_layout.rs +++ b/src/codegen/struct_layout.rs @@ -20,6 +20,7 @@ pub struct StructLayoutTracker<'a> { is_packed: bool, known_type_layout: Option<Layout>, is_rust_union: bool, + can_copy_union_fields: bool, latest_offset: usize, padding_count: usize, latest_field_layout: Option<Layout>, @@ -90,8 +91,8 @@ impl<'a> StructLayoutTracker<'a> { ) -> Self { let known_type_layout = ty.layout(ctx); let is_packed = comp.is_packed(ctx, known_type_layout.as_ref()); - let is_rust_union = comp.is_union() && - comp.can_be_rust_union(ctx, known_type_layout.as_ref()); + let (is_rust_union, can_copy_union_fields) = + comp.is_rust_union(ctx, known_type_layout.as_ref(), name); StructLayoutTracker { name, ctx, @@ -99,6 +100,7 @@ impl<'a> StructLayoutTracker<'a> { is_packed, known_type_layout, is_rust_union, + can_copy_union_fields, latest_offset: 0, padding_count: 0, latest_field_layout: None, @@ -107,6 +109,10 @@ impl<'a> StructLayoutTracker<'a> { } } + pub fn can_copy_union_fields(&self) -> bool { + self.can_copy_union_fields + } + pub fn is_rust_union(&self) -> bool { self.is_rust_union } diff --git a/src/ir/comp.rs b/src/ir/comp.rs index fdf6a963..f44c5d67 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -14,6 +14,7 @@ use crate::codegen::struct_layout::{align_to, bytes_from_bits_pow2}; use crate::ir::derive::CanDeriveCopy; use crate::parse::{ClangItemParser, ParseError}; use crate::HashMap; +use crate::NonCopyUnionStyle; use peeking_take_while::PeekableExt; use std::cmp; use std::io; @@ -1680,21 +1681,37 @@ impl CompInfo { /// /// Requirements: /// 1. Current RustTarget allows for `untagged_union` - /// 2. Each field can derive `Copy` + /// 2. Each field can derive `Copy` or we use ManuallyDrop. /// 3. It's not zero-sized. - pub fn can_be_rust_union( + /// + /// Second boolean returns whether all fields can be copied (and thus + /// ManuallyDrop is not needed). + pub fn is_rust_union( &self, ctx: &BindgenContext, layout: Option<&Layout>, - ) -> bool { + name: &str, + ) -> (bool, bool) { + if !self.is_union() { + return (false, false); + } + if !ctx.options().rust_features().untagged_union { - return false; + return (false, false); } if self.is_forward_declaration() { - return false; + return (false, false); } + let union_style = if ctx.options().bindgen_wrapper_union.matches(name) { + NonCopyUnionStyle::BindgenWrapper + } else if ctx.options().manually_drop_union.matches(name) { + NonCopyUnionStyle::ManuallyDrop + } else { + ctx.options().default_non_copy_union_style + }; + let all_can_copy = self.fields().iter().all(|f| match *f { Field::DataMember(ref field_data) => { field_data.ty().can_derive_copy(ctx) @@ -1702,15 +1719,15 @@ impl CompInfo { Field::Bitfields(_) => true, }); - if !all_can_copy { - return false; + if !all_can_copy && union_style == NonCopyUnionStyle::BindgenWrapper { + return (false, false); } if layout.map_or(false, |l| l.size == 0) { - return false; + return (false, false); } - true + (true, all_can_copy) } } |