Skip to content

Add bitfield allocation unit constructors #707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 19, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions bindgen-integration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,40 @@ fn test_bitfields_third() {
});
}

#[test]
fn test_bitfield_constructors() {
let mut first = bindings::bitfields::First {
_bitfield_1: bindings::bitfields::First::new_bitfield_1(1),
_bitfield_2: bindings::bitfields::First::new_bitfield_2(2, 3),
__bindgen_align: [],
};
assert!(unsafe {
first.assert(1, 2, 3)
});

let mut second = bindings::bitfields::Second {
_bitfield_1: bindings::bitfields::Second::new_bitfield_1(1337, true),
__bindgen_align: [],
};
assert!(unsafe {
second.assert(1337, true)
});

let mut third = bindings::bitfields::Third {
_bitfield_1: bindings::bitfields::Third::new_bitfield_1(
42,
false,
bindings::bitfields::ItemKind::ITEM_KIND_TRES
),
__bindgen_align: [],
};
assert!(unsafe {
third.assert(42,
false,
bindings::bitfields::ItemKind::ITEM_KIND_TRES)
});
}

impl Drop for bindings::AutoRestoreBool {
fn drop(&mut self) {
unsafe { bindings::AutoRestoreBool::destruct(self) }
Expand Down
121 changes: 120 additions & 1 deletion src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,108 @@ impl<'a> FieldCodegen<'a> for FieldData {
}
}

impl BitfieldUnit {
/// Get the constructor name for this bitfield unit.
fn ctor_name(&self, ctx: &BindgenContext) -> ast::Ident {
let ctor_name = format!("new_bitfield_{}", self.nth());
ctx.ext_cx().ident_of(&ctor_name)
}

/// Get the initial bitfield unit constructor that just returns 0. This will
/// then be extended by each bitfield in the unit. See `extend_ctor_impl`
/// below.
fn initial_ctor_impl(&self,
ctx: &BindgenContext,
unit_field_int_ty: &P<ast::Ty>)
-> P<ast::Item> {
let ctor_name = self.ctor_name(ctx);

// If we're generating unstable Rust, add the const.
let fn_prefix = if ctx.options().unstable_rust {
quote_tokens!(ctx.ext_cx(), pub const fn)
} else {
quote_tokens!(ctx.ext_cx(), pub fn)
};

quote_item!(
ctx.ext_cx(),
impl XxxUnused {
#[inline]
$fn_prefix $ctor_name() -> $unit_field_int_ty {
0
}
}
).unwrap()
}
}

impl Bitfield {
/// Extend an under construction bitfield unit constructor with this
/// bitfield. This involves two things:
///
/// 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.
fn extend_ctor_impl(&self,
ctx: &BindgenContext,
parent: &CompInfo,
ctor_impl: P<ast::Item>,
ctor_name: &ast::Ident,
unit_field_int_ty: &P<ast::Ty>)
-> P<ast::Item> {
match ctor_impl.unwrap().node {
ast::ItemKind::Impl(_, _, _, _, _, ref items) => {
assert_eq!(items.len(), 1);

match items.get(0).unwrap().node {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure just doing items[0] will yield a better error message. Can't it be done that way?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I think this method may be more readable writing it as:

let items = match ctor_impl.unwrap().node {
    ast::ItemKind::Impl(_, _, ..., items) => items,
    _ => unreachable!(),
};

assert_eq!(items.len(), 1);
let (sig, body) = match items[0].node {
    ast::ImplItemKind::Method(sig, body) => (sig, body),
    _ => unreachable!(),
};

// ...

ast::ImplItemKind::Method(ref sig, ref body) => {
let params = sig.decl.clone().unwrap().inputs;
let param_name = bitfield_getter_name(ctx, parent, self.name());

let bitfield_ty_item = ctx.resolve_item(self.ty());
let bitfield_ty = bitfield_ty_item.expect_type();
let bitfield_ty_layout = bitfield_ty.layout(ctx)
.expect("Bitfield without layout? Gah!");
let bitfield_int_ty = BlobTyBuilder::new(bitfield_ty_layout).build();
let bitfield_ty = bitfield_ty
.to_rust_ty_or_opaque(ctx, bitfield_ty_item);

let offset = self.offset_into_unit();
let mask = self.mask();

// If we're generating unstable Rust, add the const.
let fn_prefix = if ctx.options().unstable_rust {
quote_tokens!(ctx.ext_cx(), pub const fn)
} else {
quote_tokens!(ctx.ext_cx(), pub fn)
};

quote_item!(
ctx.ext_cx(),
impl XxxUnused {
#[inline]
$fn_prefix $ctor_name($params $param_name : $bitfield_ty)
-> $unit_field_int_ty {
let bitfield_unit_val = $body;
let $param_name = $param_name
as $bitfield_int_ty
as $unit_field_int_ty;
let mask = $mask as $unit_field_int_ty;
let $param_name = ($param_name << $offset) & mask;
bitfield_unit_val | $param_name
}
}
).unwrap()
}
_ => unreachable!(),
}
}
_ => unreachable!(),
}
}
}

impl<'a> FieldCodegen<'a> for BitfieldUnit {
type Extra = ();

Expand Down Expand Up @@ -1058,6 +1160,9 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
}
};

let ctor_name = self.ctor_name(ctx);
let mut ctor_impl = self.initial_ctor_impl(ctx, &unit_field_int_ty);

for bf in self.bitfields() {
bf.codegen(ctx,
fields_should_be_private,
Expand All @@ -1069,8 +1174,22 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
fields,
methods,
(&unit_field_name, unit_field_int_ty.clone()));

ctor_impl = bf.extend_ctor_impl(ctx,
parent,
ctor_impl,
&ctor_name,
&unit_field_int_ty);
}

match ctor_impl.unwrap().node {
ast::ItemKind::Impl(_, _, _, _, _, items) => {
assert_eq!(items.len(), 1);
methods.extend(items.into_iter());
},
_ => unreachable!(),
};

struct_layout.saw_bitfield_unit(self.layout());
}
}
Expand Down Expand Up @@ -1154,7 +1273,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);

let offset = self.offset_into_unit();
let mask: usize = ((1usize << self.width()) - 1usize) << offset;
let mask: usize = self.mask();

let impl_item = quote_item!(
ctx.ext_cx(),
Expand Down
6 changes: 6 additions & 0 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,12 @@ impl Bitfield {
self.offset_into_unit
}

/// Get the mask value that when &'ed with this bitfield's allocation unit
/// produces this bitfield's value.
pub fn mask(&self) -> usize {
((1usize << self.width()) - 1usize) << self.offset_into_unit()
}

/// Get the bit width of this bitfield.
pub fn width(&self) -> u32 {
self.data.bitfield().unwrap()
Expand Down
10 changes: 10 additions & 0 deletions tests/expectations/tests/bitfield-method-same-name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ impl Foo {
self._bitfield_1 = unsafe { ::std::mem::transmute(unit_field_val) };
}
#[inline]
pub fn new_bitfield_1(type__bindgen_bitfield: ::std::os::raw::c_char)
-> u8 {
let bitfield_unit_val = { 0 };
let type__bindgen_bitfield = type__bindgen_bitfield as u8 as u8;
let mask = 7usize as u8;
let type__bindgen_bitfield =
(type__bindgen_bitfield << 0usize) & mask;
bitfield_unit_val | type__bindgen_bitfield
}
#[inline]
pub unsafe fn type_(&mut self) -> ::std::os::raw::c_char {
Foo_type(self)
}
Expand Down
Loading