Skip to content

Commit a7f44bd

Browse files
committed
Add bitfield allocation unit constructors
This commit gives bindgen the ability to generate constructors for bitfield allocation units. This enables more ergonomic use of struct literals for bindings structs that contain bitfields. Additionally, when we are generating unstable Rust, these constructors are marked as const functions. This enables the creation of const binding structs that contain bitfields.
1 parent cabfac7 commit a7f44bd

14 files changed

+846
-1
lines changed

bindgen-integration/src/lib.rs

+34
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,40 @@ fn test_bitfields_third() {
102102
});
103103
}
104104

105+
#[test]
106+
fn test_bitfield_constructors() {
107+
let mut first = bindings::bitfields::First {
108+
_bitfield_1: bindings::bitfields::First::new_bitfield_1(1),
109+
_bitfield_2: bindings::bitfields::First::new_bitfield_2(2, 3),
110+
__bindgen_align: [],
111+
};
112+
assert!(unsafe {
113+
first.assert(1, 2, 3)
114+
});
115+
116+
let mut second = bindings::bitfields::Second {
117+
_bitfield_1: bindings::bitfields::Second::new_bitfield_1(1337, true),
118+
__bindgen_align: [],
119+
};
120+
assert!(unsafe {
121+
second.assert(1337, true)
122+
});
123+
124+
let mut third = bindings::bitfields::Third {
125+
_bitfield_1: bindings::bitfields::Third::new_bitfield_1(
126+
42,
127+
false,
128+
bindings::bitfields::ItemKind::ITEM_KIND_TRES
129+
),
130+
__bindgen_align: [],
131+
};
132+
assert!(unsafe {
133+
third.assert(42,
134+
false,
135+
bindings::bitfields::ItemKind::ITEM_KIND_TRES)
136+
});
137+
}
138+
105139
impl Drop for bindings::AutoRestoreBool {
106140
fn drop(&mut self) {
107141
unsafe { bindings::AutoRestoreBool::destruct(self) }

src/codegen/mod.rs

+120-1
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,108 @@ impl<'a> FieldCodegen<'a> for FieldData {
10201020
}
10211021
}
10221022

1023+
impl BitfieldUnit {
1024+
/// Get the constructor name for this bitfield unit.
1025+
fn ctor_name(&self, ctx: &BindgenContext) -> ast::Ident {
1026+
let ctor_name = format!("new_bitfield_{}", self.nth());
1027+
ctx.ext_cx().ident_of(&ctor_name)
1028+
}
1029+
1030+
/// Get the initial bitfield unit constructor that just returns 0. This will
1031+
/// then be extended by each bitfield in the unit. See `extend_ctor_impl`
1032+
/// below.
1033+
fn initial_ctor_impl(&self,
1034+
ctx: &BindgenContext,
1035+
unit_field_int_ty: &P<ast::Ty>)
1036+
-> P<ast::Item> {
1037+
let ctor_name = self.ctor_name(ctx);
1038+
1039+
// If we're generating unstable Rust, add the const.
1040+
let fn_prefix = if ctx.options().unstable_rust {
1041+
quote_tokens!(ctx.ext_cx(), pub const fn)
1042+
} else {
1043+
quote_tokens!(ctx.ext_cx(), pub fn)
1044+
};
1045+
1046+
quote_item!(
1047+
ctx.ext_cx(),
1048+
impl XxxUnused {
1049+
#[inline]
1050+
$fn_prefix $ctor_name() -> $unit_field_int_ty {
1051+
0
1052+
}
1053+
}
1054+
).unwrap()
1055+
}
1056+
}
1057+
1058+
impl Bitfield {
1059+
/// Extend an under construction bitfield unit constructor with this
1060+
/// bitfield. This involves two things:
1061+
///
1062+
/// 1. Adding a parameter with this bitfield's name and its type.
1063+
///
1064+
/// 2. Bitwise or'ing the parameter into the final value of the constructed
1065+
/// bitfield unit.
1066+
fn extend_ctor_impl(&self,
1067+
ctx: &BindgenContext,
1068+
parent: &CompInfo,
1069+
ctor_impl: P<ast::Item>,
1070+
ctor_name: &ast::Ident,
1071+
unit_field_int_ty: &P<ast::Ty>)
1072+
-> P<ast::Item> {
1073+
match ctor_impl.unwrap().node {
1074+
ast::ItemKind::Impl(_, _, _, _, _, ref items) => {
1075+
assert_eq!(items.len(), 1);
1076+
1077+
match items.get(0).unwrap().node {
1078+
ast::ImplItemKind::Method(ref sig, ref body) => {
1079+
let params = sig.decl.clone().unwrap().inputs;
1080+
let param_name = bitfield_getter_name(ctx, parent, self.name());
1081+
1082+
let bitfield_ty_item = ctx.resolve_item(self.ty());
1083+
let bitfield_ty = bitfield_ty_item.expect_type();
1084+
let bitfield_ty_layout = bitfield_ty.layout(ctx)
1085+
.expect("Bitfield without layout? Gah!");
1086+
let bitfield_int_ty = BlobTyBuilder::new(bitfield_ty_layout).build();
1087+
let bitfield_ty = bitfield_ty
1088+
.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
1089+
1090+
let offset = self.offset_into_unit();
1091+
let mask = self.mask();
1092+
1093+
// If we're generating unstable Rust, add the const.
1094+
let fn_prefix = if ctx.options().unstable_rust {
1095+
quote_tokens!(ctx.ext_cx(), pub const fn)
1096+
} else {
1097+
quote_tokens!(ctx.ext_cx(), pub fn)
1098+
};
1099+
1100+
quote_item!(
1101+
ctx.ext_cx(),
1102+
impl XxxUnused {
1103+
#[inline]
1104+
$fn_prefix $ctor_name($params $param_name : $bitfield_ty)
1105+
-> $unit_field_int_ty {
1106+
let bitfield_unit_val = $body;
1107+
let $param_name = $param_name
1108+
as $bitfield_int_ty
1109+
as $unit_field_int_ty;
1110+
let mask = $mask as $unit_field_int_ty;
1111+
let $param_name = ($param_name << $offset) & mask;
1112+
bitfield_unit_val | $param_name
1113+
}
1114+
}
1115+
).unwrap()
1116+
}
1117+
_ => unreachable!(),
1118+
}
1119+
}
1120+
_ => unreachable!(),
1121+
}
1122+
}
1123+
}
1124+
10231125
impl<'a> FieldCodegen<'a> for BitfieldUnit {
10241126
type Extra = ();
10251127

@@ -1058,6 +1160,9 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
10581160
}
10591161
};
10601162

1163+
let ctor_name = self.ctor_name(ctx);
1164+
let mut ctor_impl = self.initial_ctor_impl(ctx, &unit_field_int_ty);
1165+
10611166
for bf in self.bitfields() {
10621167
bf.codegen(ctx,
10631168
fields_should_be_private,
@@ -1069,8 +1174,22 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
10691174
fields,
10701175
methods,
10711176
(&unit_field_name, unit_field_int_ty.clone()));
1177+
1178+
ctor_impl = bf.extend_ctor_impl(ctx,
1179+
parent,
1180+
ctor_impl,
1181+
&ctor_name,
1182+
&unit_field_int_ty);
10721183
}
10731184

1185+
match ctor_impl.unwrap().node {
1186+
ast::ItemKind::Impl(_, _, _, _, _, items) => {
1187+
assert_eq!(items.len(), 1);
1188+
methods.extend(items.into_iter());
1189+
},
1190+
_ => unreachable!(),
1191+
};
1192+
10741193
struct_layout.saw_bitfield_unit(self.layout());
10751194
}
10761195
}
@@ -1154,7 +1273,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
11541273
let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
11551274

11561275
let offset = self.offset_into_unit();
1157-
let mask: usize = ((1usize << self.width()) - 1usize) << offset;
1276+
let mask: usize = self.mask();
11581277

11591278
let impl_item = quote_item!(
11601279
ctx.ext_cx(),

src/ir/comp.rs

+6
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,12 @@ impl Bitfield {
291291
self.offset_into_unit
292292
}
293293

294+
/// Get the mask value that when &'ed with this bitfield's allocation unit
295+
/// produces this bitfield's value.
296+
pub fn mask(&self) -> usize {
297+
((1usize << self.width()) - 1usize) << self.offset_into_unit()
298+
}
299+
294300
/// Get the bit width of this bitfield.
295301
pub fn width(&self) -> u32 {
296302
self.data.bitfield().unwrap()

tests/expectations/tests/bitfield-method-same-name.rs

+10
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ impl Foo {
5353
self._bitfield_1 = unsafe { ::std::mem::transmute(unit_field_val) };
5454
}
5555
#[inline]
56+
pub fn new_bitfield_1(type__bindgen_bitfield: ::std::os::raw::c_char)
57+
-> u8 {
58+
let bitfield_unit_val = { 0 };
59+
let type__bindgen_bitfield = type__bindgen_bitfield as u8 as u8;
60+
let mask = 7usize as u8;
61+
let type__bindgen_bitfield =
62+
(type__bindgen_bitfield << 0usize) & mask;
63+
bitfield_unit_val | type__bindgen_bitfield
64+
}
65+
#[inline]
5666
pub unsafe fn type_(&mut self) -> ::std::os::raw::c_char {
5767
Foo_type(self)
5868
}

0 commit comments

Comments
 (0)