summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <me@emiliocobos.me>2016-04-03 00:12:33 +0200
committerEmilio Cobos Álvarez <me@emiliocobos.me>2016-04-03 00:12:33 +0200
commitb925d3ec6a5fc52dd8a00acef7a8062f346eed2d (patch)
treef5cf562c5c48965eb8b7e534a7c74ebf7a28a6e7
parent6b9c662672e04045c8c65aeddcf32abf8a2d9772 (diff)
gen: parser: Rework bitfield implementation to support enums
I've probably messed something up, I know it... also we assume the width is 8 bits, which might be wrong, but I'll add it in a followup.
-rw-r--r--src/gen.rs71
-rw-r--r--src/parser.rs22
-rw-r--r--tests/headers/weird_bitfields.hpp32
3 files changed, 87 insertions, 38 deletions
diff --git a/src/gen.rs b/src/gen.rs
index a166b58b..4869583f 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -1011,20 +1011,25 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
has_destructor = true;
}
- let f_name = match f.bitfields {
+ let (f_name, f_ty) = match f.bitfields {
Some(_) => {
bitfields += 1;
- format!("_bitfield_{}", bitfields)
+ // XXX(emilio): This is probably wrong for most bitfields, where the with is
+ // greater than 8. Should probably get the width of the bitfields and adjust
+ // the generated type and layout based on that.
+ (format!("_bitfield_{}", bitfields), TInt(IUChar, Layout::new(1, 1)))
}
- None => rust_type_id(ctx, &f.name)
+ None => (rust_type_id(ctx, &f.name), f.ty.clone())
};
- let is_translatable = cty_is_translatable(&f.ty);
- if !is_translatable || type_opaque(ctx, &f.ty) {
+ drop(f.ty); // to ensure it's not used unintentionally
+
+ let is_translatable = cty_is_translatable(&f_ty);
+ if !is_translatable || type_opaque(ctx, &f_ty) {
if !is_translatable {
- println!("{}::{} not translatable, void: {}", ci.name, f.name, f.ty == TVoid);
+ println!("{}::{} not translatable, void: {}", ci.name, f.name, f_ty == TVoid);
}
- if let Some(layout) = f.ty.layout() {
+ if let Some(layout) = f_ty.layout() {
fields.push(mk_blob_field(ctx, &f_name, layout));
}
continue;
@@ -1034,10 +1039,10 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
let mut offset: u32 = 0;
if let Some(ref bitfields) = f.bitfields {
for &(ref bf_name, bf_size) in bitfields.iter() {
- setters.push(gen_bitfield_method(ctx, &f_name, bf_name, &f.ty, offset as usize, bf_size));
+ setters.push(gen_bitfield_method(ctx, &f_name, bf_name, &f_ty, offset as usize, bf_size));
offset += bf_size;
}
- setters.push(gen_fullbitfield_method(ctx, &f_name, &f.ty, bitfields))
+ setters.push(gen_fullbitfield_method(ctx, &f_name, &f_ty, bitfields))
}
}
@@ -1048,13 +1053,13 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
bypass = true;
inner_f.ty.clone()
} else {
- f.ty.clone()
+ f_ty
}
} else {
- f.ty.clone()
+ f_ty
}
} else {
- f.ty.clone()
+ f_ty
};
// If the member is not a template argument, it needs the full path.
@@ -1596,7 +1601,7 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
methods
}
-fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32) -> ast::Ty {
+fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32, is_arg: bool) -> ast::Ty {
let input_type = if width > 16 {
"u32"
} else if width > 8 {
@@ -1604,36 +1609,43 @@ fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32) -> ast::Ty {
} else if width > 1 {
"u8"
} else {
- "bool"
+ if is_arg {
+ "bool"
+ } else {
+ "u8"
+ }
};
mk_ty(ctx, false, &[input_type.to_owned()])
}
-fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
- field_name: &String, field_type: &Type,
+fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &str,
+ field_name: &str, bitfield_type: &Type,
offset: usize, width: u32) -> ast::ImplItem {
- let input_type = type_for_bitfield_width(ctx, width);
- let field_type = cty_to_rs(ctx, &field_type, false, true);
+ let input_type = type_for_bitfield_width(ctx, width, true);
+ let equivalent_field_type = type_for_bitfield_width(ctx, width, false);
+ let field_type = cty_to_rs(ctx, &bitfield_type, false, true);
let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", field_name));
- let bindgen_ident = ctx.ext_cx.ident_of(&*bindgen_name);
+ let bindgen_ident = ctx.ext_cx.ident_of(bindgen_name);
- let node = &quote_item!(&ctx.ext_cx,
+ let item = quote_item!(&ctx.ext_cx,
impl X {
pub fn $setter_name(&mut self, val: $input_type) {
- self.$bindgen_ident &= !(((1 << $width) - 1) << $offset);
- self.$bindgen_ident |= (val as $field_type) << $offset;
+ self.$bindgen_ident = ((self.$bindgen_ident as $equivalent_field_type) & !(((1 << $width) - 1) << $offset)) as $field_type;
+ self.$bindgen_ident = ((self.$bindgen_ident as $equivalent_field_type) | ((val as $equivalent_field_type) << $offset)) as $field_type;
}
}
- ).unwrap().node;
- match node {
+ ).unwrap();
+
+ match &item.node {
&ast::ItemKind::Impl(_, _, _, _, _, ref items) => items[0].clone(),
_ => unreachable!()
}
}
fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
- field_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem {
- let field_type = cty_to_rs(ctx, field_type, false, true);
+ bitfield_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem {
+ let field_type = cty_to_rs(ctx, bitfield_type, false, true);
+ let total_width = bitfields.iter().fold(0, |acc, &(_, w)| acc + w);
let mut args = vec!();
let mut unnamed: usize = 0;
for &(ref name, width) in bitfields.iter() {
@@ -1645,7 +1657,7 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
ctx.ext_cx.ident_of(name)
};
args.push(ast::Arg {
- ty: P(type_for_bitfield_width(ctx, width)),
+ ty: P(type_for_bitfield_width(ctx, width, true)),
pat: P(ast::Pat {
id: ast::DUMMY_NODE_ID,
node: ast::PatKind::Ident(
@@ -1668,7 +1680,9 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
let stmts = Vec::with_capacity(bitfields.len() + 1);
let mut offset = 0;
+
let mut exprs = quote_expr!(&ctx.ext_cx, 0);
+
let mut unnamed: usize = 0;
for &(ref name, width) in bitfields.iter() {
let name_ident = if name.is_empty() {
@@ -1681,6 +1695,7 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
exprs = quote_expr!(&ctx.ext_cx,
$exprs | (($name_ident as $field_type) << $offset)
);
+
offset += width;
}
@@ -1699,7 +1714,7 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
decl: P(fndecl),
generics: empty_generics(),
explicit_self: respan(ctx.span, ast::SelfKind::Static),
- constness: ast::Constness::Const,
+ constness: ast::Constness::NotConst,
}, P(block)
);
diff --git a/src/parser.rs b/src/parser.rs
index 600b14a7..9469ff72 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -508,8 +508,8 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
ctx: &mut ClangParserCtx,
ci: &mut CompInfo) -> Enum_CXVisitorResult {
fn is_bitfield_continuation(field: &il::FieldInfo, ty: &il::Type, width: u32) -> bool {
- match (&field.bitfields, ty) {
- (&Some(ref bitfields), &il::TInt(_, layout)) if *ty == field.ty => {
+ match (&field.bitfields, ty.layout()) {
+ (&Some(ref bitfields), Some(layout)) => {
bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w) + width <= (layout.size * 8) as u32
},
_ => false
@@ -540,9 +540,9 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
(Some(width), Some(&mut il::CompMember::Field(ref mut field)))
if is_bitfield_continuation(field, &ty, width) => {
- if let Some(ref mut bitfields) = field.bitfields {
- bitfields.push((cursor.spelling(), width));
- } else { unreachable!() }
+ // println!("found bitfield continuation {} (width: {})", cursor.spelling(), width);
+
+ field.bitfields.as_mut().unwrap().push((cursor.spelling(), width));
return CXChildVisit_Continue;
},
// The field is the start of a new bitfield
@@ -600,11 +600,13 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
// If it's a field from an unnamed union we only have to update the name
if let Some(&mut CompMember::Field(ref mut info)) = ci.members.last_mut() {
- if let (&TComp(ref field_ty_ci), &TComp(ref ci)) = (&info.ty, &ty) {
- if field_ty_ci.borrow().was_unnamed && ci.borrow().was_unnamed &&
- field_ty_ci.borrow().name == ci.borrow().name {
- info.name = name;
- return CXChildVisit_Continue;
+ if bitfields.is_none() && info.bitfields.is_none() {
+ if let (&TComp(ref field_ty_ci), &TComp(ref ci)) = (&info.ty, &ty) {
+ if field_ty_ci.borrow().was_unnamed && ci.borrow().was_unnamed &&
+ field_ty_ci.borrow().name == ci.borrow().name {
+ info.name = name;
+ return CXChildVisit_Continue;
+ }
}
}
}
diff --git a/tests/headers/weird_bitfields.hpp b/tests/headers/weird_bitfields.hpp
new file mode 100644
index 00000000..75024090
--- /dev/null
+++ b/tests/headers/weird_bitfields.hpp
@@ -0,0 +1,32 @@
+// You can guess where this is taken from...
+enum nsStyleSVGOpacitySource {
+ eStyleSVGOpacitySource_Normal,
+ eStyleSVGOpacitySource_ContextFillOpacity,
+ eStyleSVGOpacitySource_ContextStrokeOpacity
+};
+
+class Weird {
+ unsigned int mStrokeDasharrayLength;
+ unsigned char mClipRule; // [inherited]
+ unsigned char mColorInterpolation; // [inherited] see nsStyleConsts.h
+ unsigned char mColorInterpolationFilters; // [inherited] see nsStyleConsts.h
+ unsigned char mFillRule; // [inherited] see nsStyleConsts.h
+ unsigned char mImageRendering; // [inherited] see nsStyleConsts.h
+ unsigned char mPaintOrder; // [inherited] see nsStyleConsts.h
+ unsigned char mShapeRendering; // [inherited] see nsStyleConsts.h
+ unsigned char mStrokeLinecap; // [inherited] see nsStyleConsts.h
+ unsigned char mStrokeLinejoin; // [inherited] see nsStyleConsts.h
+ unsigned char mTextAnchor; // [inherited] see nsStyleConsts.h
+ unsigned char mTextRendering; // [inherited] see nsStyleConsts.h
+
+ // In SVG glyphs, whether we inherit fill or stroke opacity from the outer
+ // text object.
+ // Use 3 bits to avoid signedness problems in MSVC.
+ nsStyleSVGOpacitySource mFillOpacitySource : 3;
+ nsStyleSVGOpacitySource mStrokeOpacitySource : 3;
+
+ // SVG glyph outer object inheritance for other properties
+ bool mStrokeDasharrayFromObject : 1;
+ bool mStrokeDashoffsetFromObject : 1;
+ bool mStrokeWidthFromObject : 1;
+};