summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-11-23 04:31:10 -0600
committerGitHub <noreply@github.com>2017-11-23 04:31:10 -0600
commit7c3584d7bc328a01ae5352e191f1fd41bb7fb1a9 (patch)
treeace279bfdbd625d446074c01b958d7b4d44c729a /src
parente3e6c730393f97daae93c2394d4af7bc9a5183b4 (diff)
parentf0e05310b43e88e541ed011d20994c02fdcc1a3a (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-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
-rw-r--r--src/features.rs3
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: &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>,
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;
}