summaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorNick Fitzgerald <fitzgen@gmail.com>2017-10-25 17:31:21 -0700
committerGlyn Normington <gnormington@pivotal.io>2017-11-21 13:55:00 +0000
commitf0e05310b43e88e541ed011d20994c02fdcc1a3a (patch)
treebe05ee8a3fa1a1d7f696daa630e48a824276ff61 /src/codegen
parent5e0cf9c356960e0459fea22cf0754dbec66f58b4 (diff)
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. The alignment of the Storage type is intended to be no larger than the alignment of the Align type, which will be true if the Storage type is, for example, an array of u8. 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.
Diffstat (limited to 'src/codegen')
-rwxr-xr-xsrc/codegen/bitfield_unit.rs82
-rw-r--r--src/codegen/bitfield_unit_tests.rs284
-rw-r--r--src/codegen/helpers.rs42
-rw-r--r--src/codegen/mod.rs248
4 files changed, 543 insertions, 113 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 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: &quote::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>,