diff options
author | Emilio Cobos Álvarez <me@emiliocobos.me> | 2016-04-16 03:36:32 +0200 |
---|---|---|
committer | Emilio Cobos Álvarez <me@emiliocobos.me> | 2016-04-16 03:36:32 +0200 |
commit | 731e4bd32ae5307a6604da047ffd38be4b2c1f96 (patch) | |
tree | 2421505af9f2f7a50fb49c3f55573562763a6b5a | |
parent | e7c644ed4aa0e3040851571b177d39c10efa001b (diff) |
Large-ish refactor that should fix a *lot* of errors
-rw-r--r-- | src/gen.rs | 73 | ||||
-rw-r--r-- | src/parser.rs | 58 | ||||
-rw-r--r-- | src/types.rs | 84 |
3 files changed, 144 insertions, 71 deletions
@@ -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 + } + } } } |