diff options
Diffstat (limited to 'src/codegen/mod.rs')
-rw-r--r-- | src/codegen/mod.rs | 248 |
1 files changed, 142 insertions, 106 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index f0a7e0be..bfc32129 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -4,6 +4,12 @@ mod error; mod helpers; pub mod struct_layout; +#[cfg(test)] +#[allow(warnings)] +pub(crate) mod bitfield_unit; +#[cfg(test)] +mod bitfield_unit_tests; + use self::helpers::attributes; use self::struct_layout::StructLayoutTracker; @@ -96,6 +102,9 @@ struct CodegenResult<'a> { /// Whether Objective C types have been seen at least once. saw_objc: bool, + /// Whether a bitfield allocation unit has been seen at least once. + saw_bitfield_unit: bool, + items_seen: HashSet<ItemId>, /// The set of generated function/var names, needed because in C/C++ is /// legal to do something like: @@ -130,6 +139,7 @@ impl<'a> CodegenResult<'a> { saw_bindgen_union: false, saw_incomplete_array: false, saw_objc: false, + saw_bitfield_unit: false, codegen_id: codegen_id, items_seen: Default::default(), functions_seen: Default::default(), @@ -155,6 +165,10 @@ impl<'a> CodegenResult<'a> { self.saw_objc = true; } + fn saw_bitfield_unit(&mut self) { + self.saw_bitfield_unit = true; + } + fn seen<Id: Into<ItemId>>(&self, item: Id) -> bool { self.items_seen.contains(&item.into()) } @@ -200,6 +214,7 @@ impl<'a> CodegenResult<'a> { self.saw_union |= new.saw_union; self.saw_incomplete_array |= new.saw_incomplete_array; self.saw_objc |= new.saw_objc; + self.saw_bitfield_unit |= new.saw_bitfield_unit; new.items } @@ -395,6 +410,9 @@ impl CodeGenerator for Module { if result.saw_objc { utils::prepend_objc_header(ctx, &mut *result); } + if result.saw_bitfield_unit { + utils::prepend_bitfield_unit_type(&mut *result); + } } }; @@ -1119,14 +1137,13 @@ impl Bitfield { /// /// 1. Adding a parameter with this bitfield's name and its type. /// - /// 2. Bitwise or'ing the parameter into the final value of the constructed - /// bitfield unit. + /// 2. Setting the relevant bits on the `__bindgen_bitfield_unit` variable + /// that's being constructed. fn extend_ctor_impl( &self, ctx: &BindgenContext, param_name: quote::Tokens, - ctor_impl: quote::Tokens, - unit_field_int_ty: "e::Tokens, + mut ctor_impl: quote::Tokens, ) -> quote::Tokens { let bitfield_ty = ctx.resolve_type(self.ty()); let bitfield_ty_layout = bitfield_ty.layout(ctx).expect( @@ -1135,15 +1152,23 @@ impl Bitfield { let bitfield_int_ty = helpers::blob(bitfield_ty_layout); let offset = self.offset_into_unit(); - let mask = helpers::ast_ty::hex_expr(self.mask()); + let width = self.width() as u8; + let prefix = ctx.trait_prefix(); - // Don't use variables or blocks because const functions do not allow - // them. - quote! { - (#ctor_impl | - ((#param_name as #bitfield_int_ty as #unit_field_int_ty) << #offset) & - (#mask as #unit_field_int_ty)) - } + ctor_impl.append(quote! { + __bindgen_bitfield_unit.set( + #offset, + #width, + { + let #param_name: #bitfield_int_ty = unsafe { + ::#prefix::mem::transmute(#param_name) + }; + #param_name as u64 + } + ); + }); + + ctor_impl } } @@ -1166,19 +1191,23 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { F: Extend<quote::Tokens>, M: Extend<quote::Tokens>, { - let field_ty = if parent.is_union() && !parent.can_be_rust_union(ctx) { - let ty = helpers::blob(self.layout()); - if ctx.options().enable_cxx_namespaces { - quote! { - root::__BindgenUnionField<#ty> + result.saw_bitfield_unit(); + + let field_ty = { + let ty = helpers::bitfield_unit(ctx, self.layout()); + if parent.is_union() && !parent.can_be_rust_union(ctx) { + if ctx.options().enable_cxx_namespaces { + quote! { + root::__BindgenUnionField<#ty> + } + } else { + quote! { + __BindgenUnionField<#ty> + } } } else { - quote! { - __BindgenUnionField<#ty> - } + ty } - } else { - helpers::blob(self.layout()) }; let unit_field_name = format!("_bitfield_{}", self.nth()); @@ -1189,34 +1218,21 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { }; fields.extend(Some(field)); - let mut field_int_size = self.layout().size; - if !field_int_size.is_power_of_two() { - field_int_size = field_int_size.next_power_of_two(); - } - - let unit_field_int_ty = match field_int_size { - 8 => quote! { u64 }, - 4 => quote! { u32 }, - 2 => quote! { u16 }, - 1 => quote! { u8 }, - size => { - debug_assert!(size > 8); - // Can't generate bitfield accessors for unit sizes larger than - // 64 bits at the moment. - struct_layout.saw_bitfield_unit(self.layout()); - return; - } - }; + let unit_field_ty = helpers::bitfield_unit(ctx, self.layout()); let ctor_name = self.ctor_name(); let mut ctor_params = vec![]; - let mut ctor_impl = quote! { 0 }; + let mut ctor_impl = quote! {}; + let mut generate_ctor = true; for bf in self.bitfields() { // Codegen not allowed for anonymous bitfields if bf.name().is_none() { continue; } + + let mut bitfield_representable_as_int = true; + bf.codegen( ctx, fields_should_be_private, @@ -1227,9 +1243,15 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { struct_layout, fields, methods, - (&unit_field_name, unit_field_int_ty.clone(), self.layout().size), + (&unit_field_name, &mut bitfield_representable_as_int), ); + // Generating a constructor requires the bitfield to be representable as an integer. + if !bitfield_representable_as_int { + generate_ctor = false; + continue; + } + let param_name = bitfield_getter_name(ctx, bf); let bitfield_ty_item = ctx.resolve_item(bf.ty()); let bitfield_ty = bitfield_ty_item.expect_type(); @@ -1243,22 +1265,19 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { ctx, param_name, ctor_impl, - &unit_field_int_ty, ); } - let const_ = if ctx.options().rust_features().const_fn() { - quote! { const } - } else { - quote! { } - }; - - methods.extend(Some(quote! { - #[inline] - pub #const_ fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_int_ty { - #ctor_impl - } - })); + if generate_ctor { + methods.extend(Some(quote! { + #[inline] + pub fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty { + let mut __bindgen_bitfield_unit: #unit_field_ty = Default::default(); + #ctor_impl + __bindgen_bitfield_unit + } + })); + } struct_layout.saw_bitfield_unit(self.layout()); } @@ -1283,7 +1302,7 @@ fn bitfield_setter_name( } impl<'a> FieldCodegen<'a> for Bitfield { - type Extra = (&'a str, quote::Tokens, usize); + type Extra = (&'a str, &'a mut bool); fn codegen<F, M>( &self, @@ -1291,12 +1310,12 @@ impl<'a> FieldCodegen<'a> for Bitfield { _fields_should_be_private: bool, _codegen_depth: usize, _accessor_kind: FieldAccessorKind, - _parent: &CompInfo, + parent: &CompInfo, _result: &mut CodegenResult, _struct_layout: &mut StructLayoutTracker, _fields: &mut F, methods: &mut M, - (unit_field_name, unit_field_int_ty, unit_field_size): (&'a str, quote::Tokens, usize), + (unit_field_name, bitfield_representable_as_int): (&'a str, &mut bool), ) where F: Extend<quote::Tokens>, M: Extend<quote::Tokens>, @@ -1312,65 +1331,73 @@ impl<'a> FieldCodegen<'a> for Bitfield { let bitfield_ty_layout = bitfield_ty.layout(ctx).expect( "Bitfield without layout? Gah!", ); - let bitfield_int_ty = helpers::blob(bitfield_ty_layout); + let bitfield_int_ty = match helpers::integer_type(bitfield_ty_layout) { + Some(int_ty) => { + *bitfield_representable_as_int = true; + int_ty + } + None => { + *bitfield_representable_as_int = false; + return; + } + }; let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); let offset = self.offset_into_unit(); - let mask = helpers::ast_ty::hex_expr(self.mask()); - methods.extend(Some(quote! { - #[inline] - pub fn #getter_name(&self) -> #bitfield_ty { - let mut unit_field_val: #unit_field_int_ty = unsafe { - ::#prefix::mem::uninitialized() - }; + let width = self.width() as u8; - unsafe { - ::#prefix::ptr::copy_nonoverlapping( - &self.#unit_field_ident as *const _ as *const u8, - &mut unit_field_val as *mut #unit_field_int_ty as *mut u8, - #unit_field_size, - ) - }; - - let mask = #mask as #unit_field_int_ty; - let val = (unit_field_val & mask) >> #offset; - unsafe { - ::#prefix::mem::transmute(val as #bitfield_int_ty) + if parent.is_union() && !parent.can_be_rust_union(ctx) { + methods.extend(Some(quote! { + #[inline] + pub fn #getter_name(&self) -> #bitfield_ty { + unsafe { + ::#prefix::mem::transmute( + self.#unit_field_ident.as_ref().get(#offset, #width) + as #bitfield_int_ty + ) + } } - } - #[inline] - pub fn #setter_name(&mut self, val: #bitfield_ty) { - let mask = #mask as #unit_field_int_ty; - let val = val as #bitfield_int_ty as #unit_field_int_ty; - - let mut unit_field_val: #unit_field_int_ty = unsafe { - ::#prefix::mem::uninitialized() - }; - - unsafe { - ::#prefix::ptr::copy_nonoverlapping( - &self.#unit_field_ident as *const _ as *const u8, - &mut unit_field_val as *mut #unit_field_int_ty as *mut u8, - #unit_field_size, - ) - }; - - unit_field_val &= !mask; - unit_field_val |= (val << #offset) & mask; + #[inline] + pub fn #setter_name(&mut self, val: #bitfield_ty) { + unsafe { + let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); + self.#unit_field_ident.as_mut().set( + #offset, + #width, + val as u64 + ) + } + } + })); + } else { + methods.extend(Some(quote! { + #[inline] + pub fn #getter_name(&self) -> #bitfield_ty { + unsafe { + ::#prefix::mem::transmute( + self.#unit_field_ident.get(#offset, #width) + as #bitfield_int_ty + ) + } + } - unsafe { - ::#prefix::ptr::copy_nonoverlapping( - &unit_field_val as *const _ as *const u8, - &mut self.#unit_field_ident as *mut _ as *mut u8, - #unit_field_size, - ); + #[inline] + pub fn #setter_name(&mut self, val: #bitfield_ty) { + unsafe { + let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); + self.#unit_field_ident.set( + #offset, + #width, + val as u64 + ) + } } - } - })); + })); + } } } @@ -3393,6 +3420,15 @@ mod utils { use quote; use std::mem; + pub fn prepend_bitfield_unit_type(result: &mut Vec<quote::Tokens>) { + let mut bitfield_unit_type = quote! {}; + bitfield_unit_type.append(include_str!("./bitfield_unit.rs")); + + let items = vec![bitfield_unit_type]; + let old_items = mem::replace(result, items); + result.extend(old_items); + } + pub fn prepend_objc_header( ctx: &BindgenContext, result: &mut Vec<quote::Tokens>, |