summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <me@emiliocobos.me>2016-04-16 03:36:32 +0200
committerEmilio Cobos Álvarez <me@emiliocobos.me>2016-04-16 03:36:32 +0200
commit731e4bd32ae5307a6604da047ffd38be4b2c1f96 (patch)
tree2421505af9f2f7a50fb49c3f55573562763a6b5a
parente7c644ed4aa0e3040851571b177d39c10efa001b (diff)
Large-ish refactor that should fix a *lot* of errors
-rw-r--r--src/gen.rs73
-rw-r--r--src/parser.rs58
-rw-r--r--src/types.rs84
3 files changed, 144 insertions, 71 deletions
diff --git a/src/gen.rs b/src/gen.rs
index 24933abb..aa501dfd 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -778,10 +778,7 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> Vec<P<ast::Item>> {
}
if ty.opaque {
- return vec![
- mk_opaque_struct(ctx, &ty.name, &ty.layout),
- mk_test_fn(ctx, &ty.name, &ty.layout),
- ];
+ return mk_opaque_struct(ctx, &ty.name, &ty.layout);
}
let item = match ty.ty {
@@ -807,11 +804,7 @@ fn comp_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo)
if ci.opaque {
let name = first(rust_id(ctx, &ci.name));
- // The test should always be correct but...
- return vec![
- mk_opaque_struct(ctx, &name, &ci.layout),
- mk_test_fn(ctx, &name, &ci.layout),
- ];
+ return mk_opaque_struct(ctx, &name, &ci.layout);
}
match ci.kind {
@@ -991,29 +984,15 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
let (opt_rc_c, opt_f) = comp_fields(m);
if let Some(f) = opt_f {
- let (f_name, f_ty) = match f.bitfields {
+ let f_name = match f.bitfields {
Some(ref v) => {
bitfields += 1;
- // NOTE: We rely on the name of the type converted to rust types,
- // and on the alignment.
- let bits = v.iter().fold(0, |acc, &(_, w)| acc + w);
-
- let layout_size = cmp::max(1, bits.next_power_of_two() / 8) as usize;
- let name = match layout_size {
- 1 => "uint8_t",
- 2 => "uint16_t",
- 4 => "uint32_t",
- 8 => "uint64_t",
- _ => panic!("bitfield width not supported: {}", layout_size),
- };
-
- let ty = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.to_owned(), ROOT_MODULE_ID, TVoid, Layout::new(layout_size, layout_size)))));
- (format!("_bitfield_{}", bitfields), ty)
+ format!("_bitfield_{}", bitfields)
}
- None => (rust_type_id(ctx, &f.name), f.ty.clone())
+ None => rust_type_id(ctx, &f.name)
};
- drop(f.ty); // to ensure it's not used unintentionally
+ let f_ty = f.ty;
let is_translatable = cty_is_translatable(&f_ty);
if !is_translatable || f_ty.is_opaque() {
@@ -1623,8 +1602,18 @@ fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &str,
field_name: &str, field_type: &Type,
offset: usize, width: u32) -> ast::ImplItem {
let input_type = type_for_bitfield_width(ctx, width, true);
+ let width = width % (field_type.layout().unwrap().size as u32 * 8);
+
let field_type = cty_to_rs(ctx, &field_type, false, true);
- let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", field_name));
+
+ let real_field_name = if field_name.is_empty() {
+ format!("at_offset_{}", offset)
+ } else {
+ field_name.into()
+ };
+
+
+ let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", real_field_name));
let bindgen_ident = ctx.ext_cx.ident_of(bindgen_name);
let item = quote_item!(&ctx.ext_cx,
@@ -2228,7 +2217,7 @@ fn mk_test_fn(ctx: &GenCtx, name: &str, layout: &Layout) -> P<ast::Item> {
item
}
-fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> P<ast::Item> {
+fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> Vec<P<ast::Item>> {
let blob_field = mk_blob_field(ctx, "_bindgen_opaque_blob", layout);
let variant_data = if layout.size == 0 {
ast::VariantData::Unit(ast::DUMMY_NODE_ID)
@@ -2248,14 +2237,23 @@ fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> P<ast::Item> {
}
);
- P(ast::Item {
+ let struct_decl = P(ast::Item {
ident: ctx.ext_cx.ident_of(&name),
attrs: vec![mk_repr_attr(ctx, layout)],
id: ast::DUMMY_NODE_ID,
node: def,
vis: ast::Visibility::Public,
span: ctx.span
- })
+ });
+
+ let mut ret = vec![struct_decl];
+
+ // The test should always be correct but...
+ if *layout != Layout::zero() {
+ ret.push(mk_test_fn(ctx, &name, layout));
+ }
+
+ ret
}
fn gen_union_field_definitions_if_necessary(ctx: &mut GenCtx, mut root_mod: &mut ast::Item) {
@@ -2264,7 +2262,7 @@ fn gen_union_field_definitions_if_necessary(ctx: &mut GenCtx, mut root_mod: &mut
}
let union_fields_decl = quote_item!(&ctx.ext_cx,
- #[derive(Copy, Clone, Debug)]
+ #[derive(Copy, Debug)]
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
).unwrap();
@@ -2296,10 +2294,19 @@ fn gen_union_field_definitions_if_necessary(ctx: &mut GenCtx, mut root_mod: &mut
}
).unwrap();
+ let union_fields_clone_impl = quote_item!(&ctx.ext_cx,
+ impl<T> ::std::clone::Clone for __BindgenUnionField<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ Self::new()
+ }
+ }
+ ).unwrap();
+
match root_mod.node {
ast::ItemKind::Mod(ref mut root) => {
- let old_items = std::mem::replace(&mut root.items, vec![union_fields_decl, union_fields_impl, union_fields_default_impl]);
+ let old_items = std::mem::replace(&mut root.items, vec![union_fields_decl, union_fields_impl, union_fields_default_impl, union_fields_clone_impl]);
root.items.extend(old_items.into_iter());
}
_ => unreachable!(),
diff --git a/src/parser.rs b/src/parser.rs
index 843a39b0..c1601a42 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -4,6 +4,7 @@ use std::collections::{HashMap, HashSet};
use std::cell::RefCell;
use std::rc::Rc;
use std::path::Path;
+use std::cmp;
use syntax::abi;
@@ -369,8 +370,8 @@ fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx,
ci.borrow_mut().args = args;
cursor.visit(|c, _: &Cursor| {
if c.kind() == CXCursor_TemplateRef {
- let cref = c.definition();
- ci.borrow_mut().ref_template = Some(conv_decl_ty(ctx, &cref.cur_type(), &cref));
+ let decl = decl_name(ctx, &c.referenced());
+ ci.borrow_mut().ref_template = Some(decl.to_type());
}
CXChildVisit_Continue
});
@@ -383,7 +384,8 @@ fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx,
let ei = decl.enuminfo();
TEnum(ei)
}
- CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => {
+ CXCursor_TypeAliasDecl |
+ CXCursor_TypedefDecl => {
if resolve_typedefs {
return conv_ty_resolving_typedefs(ctx, &ty_decl.typedef_type(), &ty_decl.typedef_type().declaration(), resolve_typedefs);
}
@@ -533,10 +535,11 @@ impl Annotations {
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.layout()) {
+ fn is_bitfield_continuation(field: &il::FieldInfo, _ty: &il::Type, width: u32) -> bool {
+ match (&field.bitfields, field.ty.layout()) {
(&Some(ref bitfields), Some(layout)) => {
- bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w) + width <= (layout.size * 8) as u32
+ let actual_width = bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w);
+ actual_width + width <= (layout.size * 8) as u32
},
_ => false
}
@@ -553,7 +556,9 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
}
let is_class_typedef = cursor.cur_type().sanitized_spelling_in(&ci.typedefs);
- let ty = conv_ty_resolving_typedefs(ctx, &cursor.cur_type(), cursor, is_class_typedef);
+
+ // NB: Overwritten in the case of non-integer bitfield
+ let mut ty = conv_ty_resolving_typedefs(ctx, &cursor.cur_type(), cursor, is_class_typedef);
let comment = cursor.raw_comment();
let (name, bitfields) = match (cursor.bit_width(), ci.members.last_mut()) {
@@ -573,9 +578,30 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
match ty {
il::TInt(_, _) => (),
_ => {
- let msg = format!("Enums in bitfields are not supported ({}::{}).",
- parent.spelling(), cursor.spelling());
+ // NOTE: We rely on the name of the type converted to rust types,
+ // and on the alignment.
+ let bits = cmp::max(width, ty.size() as u32 * 8);
+ let layout_size = cmp::max(1, bits.next_power_of_two() / 8) as usize;
+
+ let msg = format!("Enums in bitfields are not supported ({}::{}). Trying to recover with width: {}",
+ parent.spelling(), cursor.spelling(), layout_size * 8);
ctx.logger.warn(&msg);
+
+ let name = match layout_size {
+ 1 => "uint8_t",
+ 2 => "uint16_t",
+ 4 => "uint32_t",
+ 8 => "uint64_t",
+ _ => panic!("bitfield width not supported: {}", layout_size),
+ };
+
+ // NB: We rely on the ULongLong not being translated
+ // (using the common uintxx_t name)
+ let ti = TypeInfo::new(name.into(),
+ ctx.current_module_id,
+ TInt(IKind::IULongLong, Layout::new(layout_size, layout_size)),
+ Layout::new(layout_size, layout_size));
+ ty = TNamed(Rc::new(RefCell::new(ti)))
}
}
("".to_owned(), Some(vec!((cursor.spelling(), width))))
@@ -619,15 +645,12 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
// _ => false
//};
- // 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 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;
- }
+ if info.ty.was_unnamed() && ty.was_unnamed() &&
+ info.ty.name() == ty.name() {
+ *info = FieldInfo::new(name, ty, comment, bitfields);
+ return CXChildVisit_Continue;
}
}
}
@@ -917,9 +940,6 @@ fn visit_top(cursor: &Cursor,
| CXCursor_ClassDecl
| CXCursor_ClassTemplate => {
let anno = Annotations::new(cursor);
- if anno.hide {
- return CXChildVisit_Continue;
- }
fwd_decl(ctx, cursor, move |ctx_| {
let decl = decl_name(ctx_, cursor);
let ci = decl.compinfo();
diff --git a/src/types.rs b/src/types.rs
index 586c7ea9..0d2fc8b2 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -124,6 +124,19 @@ impl Global {
_ => panic!("global_varinfo")
}
}
+
+ pub fn to_type(self) -> Type {
+ match self {
+ GType(ti) => TNamed(ti),
+ GComp(ci)
+ | GCompDecl(ci) => TComp(ci),
+ GEnum(ei)
+ | GEnumDecl(ei) => TEnum(ei),
+ GVar(_)
+ | GFunc(_)
+ | GOther => TVoid,
+ }
+ }
}
impl fmt::Debug for Global {
@@ -165,6 +178,7 @@ pub enum Type {
}
impl Type {
+ #[allow(dead_code)]
pub fn name(&self) -> Option<String> {
match *self {
TNamed(ref info) => Some(info.borrow().name.clone()),
@@ -176,6 +190,16 @@ impl Type {
}
}
+ // XXX Add this info to enums?
+ pub fn was_unnamed(&self) -> bool {
+ match *self {
+ TComp(ref ci) => ci.borrow().was_unnamed,
+ TArray(ref t, _, _) => t.was_unnamed(),
+ TPtr(ref t, _, _, _) => t.was_unnamed(),
+ _ => false,
+ }
+ }
+
pub fn size(&self) -> usize {
self.layout().map(|l| l.size).unwrap_or(0)
}
@@ -203,7 +227,7 @@ impl Type {
}
pub fn can_derive_debug(&self) -> bool {
- match *self {
+ !self.is_opaque() && match *self {
TArray(ref t, size, _) => size <= 32 && t.can_derive_debug(),
TNamed(ref ti) => ti.borrow().ty.can_derive_debug(),
TComp(ref comp) => comp.borrow().can_derive_debug(),
@@ -221,6 +245,16 @@ impl Type {
}
}
+ pub fn is_union_like(&self) -> bool {
+ match *self {
+ TArray(ref t, _, _) => t.is_union_like(),
+ TPtr(ref t, _, _, _) => t.is_union_like(),
+ TNamed(ref ti) => ti.borrow().ty.is_union_like(),
+ TComp(ref ci) => ci.borrow().kind == CompKind::Union,
+ _ => false,
+ }
+ }
+
// If a type is opaque we conservatively
// assume it has destructor
pub fn has_destructor(&self) -> bool {
@@ -236,8 +270,8 @@ impl Type {
match *self {
TVoid => false,
TArray(ref t, _, _) => t.is_translatable(),
- TNamed(ref ti) => ti.borrow().ty.is_translatable(),
TComp(ref ci) => ci.borrow().is_translatable(),
+ // NB: TNamed explicitely ommited here
_ => true,
}
}
@@ -300,7 +334,7 @@ pub enum FKind {
FDouble
}
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Debug)]
pub enum CompMember {
Field(FieldInfo),
Comp(Rc<RefCell<CompInfo>>),
@@ -434,25 +468,37 @@ impl CompInfo {
}
pub fn has_destructor(&self) -> bool {
- self.has_destructor ||
- self.ref_template.as_ref().map_or(false, |t| t.has_destructor()) ||
- self.args.iter().any(|t| t != &TVoid && t.has_destructor()) ||
- self.members.iter().enumerate().any(|(index, m)| match *m {
- CompMember::Field(ref f) |
- CompMember::CompField(_, ref f) => {
- // Base members may not be resolved yet
- if index < self.base_members {
- f.ty.has_destructor()
- } else {
- f.ty.has_destructor() || !f.ty.is_translatable()
- }
- },
- _ => false,
- })
+ self.has_destructor || match self.kind {
+ CompKind::Union => false,
+ CompKind::Struct => {
+ // NB: We can't rely on a type with type parameters
+ // not having destructor.
+ //
+ // This is unfortunate, but...
+ !self.args.is_empty() ||
+ self.members.iter().enumerate().any(|(index, m)| match *m {
+ CompMember::Field(ref f) |
+ CompMember::CompField(_, ref f) => {
+ // Base members may not be resolved yet
+ if index < self.base_members {
+ f.ty.has_destructor()
+ } else {
+ f.ty.has_destructor() || !f.ty.is_translatable()
+ }
+ },
+ _ => false,
+ })
+ }
+ }
}
pub fn is_translatable(&self) -> bool {
- self.args.iter().all(|t| t.is_translatable()) && !self.has_non_type_template_params
+ match self.kind {
+ CompKind::Union => true,
+ CompKind::Struct => {
+ self.args.iter().all(|t| t != &TVoid) && !self.has_non_type_template_params
+ }
+ }
}
}