Skip to content

Commit 25150ca

Browse files
author
bors-servo
authored
Auto merge of #707 - fitzgen:bitfield-constructors, r=emilio
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. (Something necessary for Servo's usage of SpiderMonkey). r? @emilio
2 parents cabfac7 + 15b72b7 commit 25150ca

14 files changed

+849
-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

+123-1
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,111 @@ 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+
let items = match ctor_impl.unwrap().node {
1074+
ast::ItemKind::Impl(_, _, _, _, _, items) => {
1075+
items
1076+
}
1077+
_ => unreachable!(),
1078+
};
1079+
1080+
assert_eq!(items.len(), 1);
1081+
let (sig, body) = match items[0].node {
1082+
ast::ImplItemKind::Method(ref sig, ref body) => {
1083+
(sig, body)
1084+
}
1085+
_ => unreachable!(),
1086+
};
1087+
1088+
let params = sig.decl.clone().unwrap().inputs;
1089+
let param_name = bitfield_getter_name(ctx, parent, self.name());
1090+
1091+
let bitfield_ty_item = ctx.resolve_item(self.ty());
1092+
let bitfield_ty = bitfield_ty_item.expect_type();
1093+
let bitfield_ty_layout = bitfield_ty.layout(ctx)
1094+
.expect("Bitfield without layout? Gah!");
1095+
let bitfield_int_ty = BlobTyBuilder::new(bitfield_ty_layout).build();
1096+
let bitfield_ty = bitfield_ty
1097+
.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
1098+
1099+
let offset = self.offset_into_unit();
1100+
let mask = self.mask();
1101+
1102+
// If we're generating unstable Rust, add the const.
1103+
let fn_prefix = if ctx.options().unstable_rust {
1104+
quote_tokens!(ctx.ext_cx(), pub const fn)
1105+
} else {
1106+
quote_tokens!(ctx.ext_cx(), pub fn)
1107+
};
1108+
1109+
quote_item!(
1110+
ctx.ext_cx(),
1111+
impl XxxUnused {
1112+
#[inline]
1113+
$fn_prefix $ctor_name($params $param_name : $bitfield_ty)
1114+
-> $unit_field_int_ty {
1115+
let bitfield_unit_val = $body;
1116+
let $param_name = $param_name
1117+
as $bitfield_int_ty
1118+
as $unit_field_int_ty;
1119+
let mask = $mask as $unit_field_int_ty;
1120+
let $param_name = ($param_name << $offset) & mask;
1121+
bitfield_unit_val | $param_name
1122+
}
1123+
}
1124+
).unwrap()
1125+
}
1126+
}
1127+
10231128
impl<'a> FieldCodegen<'a> for BitfieldUnit {
10241129
type Extra = ();
10251130

@@ -1058,6 +1163,9 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
10581163
}
10591164
};
10601165

1166+
let ctor_name = self.ctor_name(ctx);
1167+
let mut ctor_impl = self.initial_ctor_impl(ctx, &unit_field_int_ty);
1168+
10611169
for bf in self.bitfields() {
10621170
bf.codegen(ctx,
10631171
fields_should_be_private,
@@ -1069,8 +1177,22 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
10691177
fields,
10701178
methods,
10711179
(&unit_field_name, unit_field_int_ty.clone()));
1180+
1181+
ctor_impl = bf.extend_ctor_impl(ctx,
1182+
parent,
1183+
ctor_impl,
1184+
&ctor_name,
1185+
&unit_field_int_ty);
10721186
}
10731187

1188+
match ctor_impl.unwrap().node {
1189+
ast::ItemKind::Impl(_, _, _, _, _, items) => {
1190+
assert_eq!(items.len(), 1);
1191+
methods.extend(items.into_iter());
1192+
},
1193+
_ => unreachable!(),
1194+
};
1195+
10741196
struct_layout.saw_bitfield_unit(self.layout());
10751197
}
10761198
}
@@ -1154,7 +1276,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
11541276
let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
11551277

11561278
let offset = self.offset_into_unit();
1157-
let mask: usize = ((1usize << self.width()) - 1usize) << offset;
1279+
let mask: usize = self.mask();
11581280

11591281
let impl_item = quote_item!(
11601282
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)