diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-11-23 04:31:10 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-23 04:31:10 -0600 |
commit | 7c3584d7bc328a01ae5352e191f1fd41bb7fb1a9 (patch) | |
tree | ace279bfdbd625d446074c01b958d7b4d44c729a /src | |
parent | e3e6c730393f97daae93c2394d4af7bc9a5183b4 (diff) | |
parent | f0e05310b43e88e541ed011d20994c02fdcc1a3a (diff) |
Auto merge of #1158 - glyn:large-bitfield-units, r=emilio
Support bitfield allocation units larger than 64 bits
Individual bitfields are still limited to at most 64 bits, but this restriction can be weakened when Rust supports `u128`.
This implements issue #816.
Usage notes:
* Since common code is added to each generated binding, a program which uses
more than one binding may need to work around the duplication by including
each binding in its own module.
* The values created by bitfield allocation unit constructors can be assigned
directly to the corresponding struct fields with no need for transmutation.
Implementation notes:
`__BindgenBitfieldUnit` represents a bitfield allocation unit using a `Storage`
type accessible as a slice of `u8`. The alignment of the unit is inherited from
an `Align` type by virtue of the field:
```
align: [Align; 0],
```
The position of this field in the struct is irrelevant.
It is assumed that the alignment of the `Storage` type is no larger than the
alignment of the `Align` type, which will be true if the `Storage` type is, for
example, an array of `u8`. This assumption is checked in a debug assertion.
Although the double underscore (__) prefix is reserved for implementations of
C++, there are precedents for this convention elsewhere in bindgen and so the
convention is adopted here too.
Acknowledgement:
Thanks to @fitzgen for an initial implementation of `__BindgenBitfieldUnit` and
code to integrate it into bindgen.
r? @emilio
Diffstat (limited to 'src')
-rwxr-xr-x | src/codegen/bitfield_unit.rs | 82 | ||||
-rw-r--r-- | src/codegen/bitfield_unit_tests.rs | 284 | ||||
-rw-r--r-- | src/codegen/helpers.rs | 42 | ||||
-rw-r--r-- | src/codegen/mod.rs | 248 | ||||
-rw-r--r-- | src/features.rs | 3 |
5 files changed, 543 insertions, 116 deletions
diff --git a/src/codegen/bitfield_unit.rs b/src/codegen/bitfield_unit.rs new file mode 100755 index 00000000..3c7c9b7b --- /dev/null +++ b/src/codegen/bitfield_unit.rs @@ -0,0 +1,82 @@ +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit<Storage, Align> +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + storage: Storage, + align: [Align; 0], +} + +impl<Storage, Align> __BindgenBitfieldUnit<Storage, Align> +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + pub fn new(storage: Storage) -> Self { + Self { + storage, + align: [], + } + } + + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + + let bit_index = index % 8; + let mask = 1 << bit_index; + + byte & mask == mask + } + + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + + let bit_index = index % 8; + let mask = 1 << bit_index; + + if val { + *byte |= mask; + } else { + *byte &= !mask; + } + } + + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + + let mut val = 0; + + for i in 0..(bit_width as usize) { + if self.get_bit(i + bit_offset) { + val |= 1 << i; + } + } + + val + } + + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + self.set_bit(i + bit_offset, val_bit_is_set); + } + } +} diff --git a/src/codegen/bitfield_unit_tests.rs b/src/codegen/bitfield_unit_tests.rs new file mode 100644 index 00000000..d39878cc --- /dev/null +++ b/src/codegen/bitfield_unit_tests.rs @@ -0,0 +1,284 @@ +//! Tests for `__BindgenBitfieldUnit`. +//! +//! Note that bit-fields are allocated right to left (least to most significant +//! bits). +//! +//! From the x86 PS ABI: +//! +//! ```c +//! struct { +//! int j : 5; +//! int k : 6; +//! int m : 7; +//! }; +//! ``` +//! +//! ```ignore +//! +------------------------------------------------------------+ +//! | | | | | +//! | padding | m | k | j | +//! |31 18|17 11|10 5|4 0| +//! +------------------------------------------------------------+ +//! ``` + +use super::bitfield_unit::__BindgenBitfieldUnit; +use std::mem; + +#[test] +fn bitfield_unit_get_bit() { + let unit = __BindgenBitfieldUnit::<[u8; 2], u64>::new([0b10011101, 0b00011101]); + + let mut bits = vec![]; + for i in 0..16 { + bits.push(unit.get_bit(i)); + } + + println!(); + println!("bits = {:?}", bits); + assert_eq!(bits, &[ + // 0b10011101 + true, + false, + true, + true, + true, + false, + false, + true , + + // 0b00011101 + true, + false, + true, + true, + true, + false, + false, + false + ]); +} + +#[test] +fn bitfield_unit_set_bit() { + let mut unit = __BindgenBitfieldUnit::<[u8; 2], u64>::new([0b00000000, 0b00000000]); + + for i in 0..16 { + if i % 3 == 0 { + unit.set_bit(i, true); + } + } + + for i in 0..16 { + assert_eq!(unit.get_bit(i), i % 3 == 0); + } + + let mut unit = __BindgenBitfieldUnit::<[u8; 2], u64>::new([0b11111111, 0b11111111]); + + for i in 0..16 { + if i % 3 == 0 { + unit.set_bit(i, false); + } + } + + for i in 0..16 { + assert_eq!(unit.get_bit(i), i % 3 != 0); + } +} + +#[test] +fn bitfield_unit_align() { + assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 1], u8>>(), mem::align_of::<u8>()); + assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 1], u16>>(), mem::align_of::<u16>()); + assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 1], u32>>(), mem::align_of::<u32>()); + assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 1], u64>>(), mem::align_of::<u64>()); + + assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 8], u8>>(), mem::align_of::<u8>()); + assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 8], u16>>(), mem::align_of::<u16>()); + assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 8], u32>>(), mem::align_of::<u32>()); + assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 8], u64>>(), mem::align_of::<u64>()); +} + +macro_rules! bitfield_unit_get { + ( + $( + With $storage:expr , then get($start:expr, $len:expr) is $expected:expr; + )* + ) => { + #[test] + fn bitfield_unit_get() { + $({ + let expected = $expected; + let unit = __BindgenBitfieldUnit::<_, u64>::new($storage); + let actual = unit.get($start, $len); + + println!(); + println!("expected = {:064b}", expected); + println!("actual = {:064b}", actual); + + assert_eq!(expected, actual); + })* + } + } +} + +bitfield_unit_get! { + // Let's just exhaustively test getting the bits from a single byte, since + // there are few enough combinations... + + With [0b11100010], then get(0, 1) is 0; + With [0b11100010], then get(1, 1) is 1; + With [0b11100010], then get(2, 1) is 0; + With [0b11100010], then get(3, 1) is 0; + With [0b11100010], then get(4, 1) is 0; + With [0b11100010], then get(5, 1) is 1; + With [0b11100010], then get(6, 1) is 1; + With [0b11100010], then get(7, 1) is 1; + + With [0b11100010], then get(0, 2) is 0b10; + With [0b11100010], then get(1, 2) is 0b01; + With [0b11100010], then get(2, 2) is 0b00; + With [0b11100010], then get(3, 2) is 0b00; + With [0b11100010], then get(4, 2) is 0b10; + With [0b11100010], then get(5, 2) is 0b11; + With [0b11100010], then get(6, 2) is 0b11; + + With [0b11100010], then get(0, 3) is 0b010; + With [0b11100010], then get(1, 3) is 0b001; + With [0b11100010], then get(2, 3) is 0b000; + With [0b11100010], then get(3, 3) is 0b100; + With [0b11100010], then get(4, 3) is 0b110; + With [0b11100010], then get(5, 3) is 0b111; + + With [0b11100010], then get(0, 4) is 0b0010; + With [0b11100010], then get(1, 4) is 0b0001; + With [0b11100010], then get(2, 4) is 0b1000; + With [0b11100010], then get(3, 4) is 0b1100; + With [0b11100010], then get(4, 4) is 0b1110; + + With [0b11100010], then get(0, 5) is 0b00010; + With [0b11100010], then get(1, 5) is 0b10001; + With [0b11100010], then get(2, 5) is 0b11000; + With [0b11100010], then get(3, 5) is 0b11100; + + With [0b11100010], then get(0, 6) is 0b100010; + With [0b11100010], then get(1, 6) is 0b110001; + With [0b11100010], then get(2, 6) is 0b111000; + + With [0b11100010], then get(0, 7) is 0b1100010; + With [0b11100010], then get(1, 7) is 0b1110001; + + With [0b11100010], then get(0, 8) is 0b11100010; + + // OK. Now let's test getting bits from across byte boundaries. + + With [0b01010101, 0b11111111, 0b00000000, 0b11111111], + then get(0, 16) is 0b1111111101010101; + + With [0b01010101, 0b11111111, 0b00000000, 0b11111111], + then get(1, 16) is 0b0111111110101010; + + With [0b01010101, 0b11111111, 0b00000000, 0b11111111], + then get(2, 16) is 0b0011111111010101; + + With [0b01010101, 0b11111111, 0b00000000, 0b11111111], + then get(3, 16) is 0b0001111111101010; + + With [0b01010101, 0b11111111, 0b00000000, 0b11111111], + then get(4, 16) is 0b0000111111110101; + + With [0b01010101, 0b11111111, 0b00000000, 0b11111111], + then get(5, 16) is 0b0000011111111010; + + With [0b01010101, 0b11111111, 0b00000000, 0b11111111], + then get(6, 16) is 0b0000001111111101; + + With [0b01010101, 0b11111111, 0b00000000, 0b11111111], + then get(7, 16) is 0b0000000111111110; + + With [0b01010101, 0b11111111, 0b00000000, 0b11111111], + then get(8, 16) is 0b0000000011111111; +} + +macro_rules! bitfield_unit_set { + ( + $( + set($start:expr, $len:expr, $val:expr) is $expected:expr; + )* + ) => { + #[test] + fn bitfield_unit_set() { + $( + let mut unit = __BindgenBitfieldUnit::<[u8; 4], u64>::new([0, 0, 0, 0]); + unit.set($start, $len, $val); + let actual = unit.get(0, 32); + + println!(); + println!("set({}, {}, {:032b}", $start, $len, $val); + println!("expected = {:064b}", $expected); + println!("actual = {:064b}", actual); + + assert_eq!($expected, actual); + )* + } + } +} + +bitfield_unit_set! { + // Once again, let's exhaustively test single byte combinations. + + set(0, 1, 0b11111111) is 0b00000001; + set(1, 1, 0b11111111) is 0b00000010; + set(2, 1, 0b11111111) is 0b00000100; + set(3, 1, 0b11111111) is 0b00001000; + set(4, 1, 0b11111111) is 0b00010000; + set(5, 1, 0b11111111) is 0b00100000; + set(6, 1, 0b11111111) is 0b01000000; + set(7, 1, 0b11111111) is 0b10000000; + + set(0, 2, 0b11111111) is 0b00000011; + set(1, 2, 0b11111111) is 0b00000110; + set(2, 2, 0b11111111) is 0b00001100; + set(3, 2, 0b11111111) is 0b00011000; + set(4, 2, 0b11111111) is 0b00110000; + set(5, 2, 0b11111111) is 0b01100000; + set(6, 2, 0b11111111) is 0b11000000; + + set(0, 3, 0b11111111) is 0b00000111; + set(1, 3, 0b11111111) is 0b00001110; + set(2, 3, 0b11111111) is 0b00011100; + set(3, 3, 0b11111111) is 0b00111000; + set(4, 3, 0b11111111) is 0b01110000; + set(5, 3, 0b11111111) is 0b11100000; + + set(0, 4, 0b11111111) is 0b00001111; + set(1, 4, 0b11111111) is 0b00011110; + set(2, 4, 0b11111111) is 0b00111100; + set(3, 4, 0b11111111) is 0b01111000; + set(4, 4, 0b11111111) is 0b11110000; + + set(0, 5, 0b11111111) is 0b00011111; + set(1, 5, 0b11111111) is 0b00111110; + set(2, 5, 0b11111111) is 0b01111100; + set(3, 5, 0b11111111) is 0b11111000; + + set(0, 6, 0b11111111) is 0b00111111; + set(1, 6, 0b11111111) is 0b01111110; + set(2, 6, 0b11111111) is 0b11111100; + + set(0, 7, 0b11111111) is 0b01111111; + set(1, 7, 0b11111111) is 0b11111110; + + set(0, 8, 0b11111111) is 0b11111111; + + // And, now let's cross byte boundaries. + + set(0, 16, 0b1111111111111111) is 0b00000000000000001111111111111111; + set(1, 16, 0b1111111111111111) is 0b00000000000000011111111111111110; + set(2, 16, 0b1111111111111111) is 0b00000000000000111111111111111100; + set(3, 16, 0b1111111111111111) is 0b00000000000001111111111111111000; + set(4, 16, 0b1111111111111111) is 0b00000000000011111111111111110000; + set(5, 16, 0b1111111111111111) is 0b00000000000111111111111111100000; + set(6, 16, 0b1111111111111111) is 0b00000000001111111111111111000000; + set(7, 16, 0b1111111111111111) is 0b00000000011111111111111110000000; + set(8, 16, 0b1111111111111111) is 0b00000000111111111111111100000000; +} diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs index 4ff398c4..99054305 100644 --- a/src/codegen/helpers.rs +++ b/src/codegen/helpers.rs @@ -1,7 +1,9 @@ //! Helpers for code generation that don't need macro expansion. +use ir::context::BindgenContext; use ir::layout::Layout; use quote; +use std::mem; pub mod attributes { use quote; @@ -86,6 +88,39 @@ pub fn blob(layout: Layout) -> quote::Tokens { } } +/// Integer type of the same size as the given `Layout`. +pub fn integer_type(layout: Layout) -> Option<quote::Tokens> { + // This guard can be weakened when Rust implements u128. + if layout.size > mem::size_of::<u64>() { + None + } else { + Some(blob(layout)) + } +} + +/// Generates a bitfield allocation unit type for a type with the given `Layout`. +pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> quote::Tokens { + let mut tokens = quote! {}; + + if ctx.options().enable_cxx_namespaces { + tokens.append(quote! { root:: }); + } + + let align = match layout.align { + n if n >= 8 => quote! { u64 }, + 4 => quote! { u32 }, + 2 => quote! { u16 }, + _ => quote! { u8 }, + }; + + let size = layout.size; + tokens.append(quote! { + __BindgenBitfieldUnit<[u8; #size], #align> + }); + + tokens +} + pub mod ast_ty { use ir::context::BindgenContext; use ir::function::FunctionSig; @@ -143,13 +178,6 @@ pub mod ast_ty { tokens } - /// Returns hex representation of the given value. - pub fn hex_expr(val: u64) -> quote::Tokens { - let mut tokens = quote! {}; - tokens.append(format!("{:#x}", val)); - tokens - } - pub fn byte_array_expr(bytes: &[u8]) -> quote::Tokens { let mut bytes: Vec<_> = bytes.iter().cloned().collect(); bytes.push(0); diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 7b700d2d..784613ba 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>, diff --git a/src/features.rs b/src/features.rs index 0954d87b..d4fbd928 100644 --- a/src/features.rs +++ b/src/features.rs @@ -140,8 +140,6 @@ macro_rules! rust_feature_def { rust_feature_def!( /// Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md)) => untagged_union; - /// Constant function ([RFC 911](https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md)) - => const_fn; /// `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202)) => thiscall_abi; /// builtin impls for `Clone` ([PR](https://github.com/rust-lang/rust/pull/43690)) @@ -161,7 +159,6 @@ impl From<RustTarget> for RustFeatures { } if rust_target >= RustTarget::Nightly { - features.const_fn = true; features.thiscall_abi = true; } |