diff options
-rw-r--r-- | src/gen.rs | 110 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/parser.rs | 117 | ||||
-rw-r--r-- | src/types.rs | 68 | ||||
-rw-r--r-- | tests/headers/annotation_hide.hpp | 4 |
5 files changed, 168 insertions, 134 deletions
@@ -376,65 +376,13 @@ fn gen_mod(mut ctx: &mut GenCtx, } } -// XXX: Replace the name-based lookup, or do it at parse-time, -// to keep all the mess in the same place. -fn type_opaque(ctx: &GenCtx, ty: &Type) -> bool { - match *ty { - TComp(ref ci) if ci.borrow().opaque => return true, - _ => {} - } - - let ty_name = ty.name(); - - match ty_name { - Some(ty_name) - => ctx.options.opaque_types.iter().any(|name| *name == ty_name), - None => false, - } -} - -fn global_opaque(ctx: &GenCtx, global: &Global) -> bool { - let global_name = global.name(); - - match *global { - GCompDecl(ref ci) | - GComp(ref ci) if ci.borrow().opaque => return true, - _ => {} - } - - // Can't make an opaque type without layout - global.layout().is_some() && - ctx.options.opaque_types.iter().any(|name| *name == global_name) -} - -fn type_blacklisted(ctx: &GenCtx, global: &Global) -> bool { - let global_name = global.name(); - - ctx.options.blacklist_type.iter().any(|name| *name == global_name) -} - fn gen_global(mut ctx: &mut GenCtx, g: Global, defs: &mut Vec<P<ast::Item>>) { - // XXX unify with anotations both type_blacklisted - // and type_opaque (which actually doesn't mean the same). - if type_blacklisted(ctx, &g) { - return; - } - - if global_opaque(ctx, &g) { - let name = first(rust_id(ctx, &g.name())); - let layout = g.layout().unwrap(); - defs.push(mk_opaque_struct(ctx, &name, &layout)); - // This should always be true but anyways.. - defs.push(mk_test_fn(ctx, &name, &layout)); - return; - } - match g { GType(ti) => { let t = ti.borrow().clone(); - defs.push(ctypedef_to_rs(&mut ctx, t)) + defs.extend(ctypedef_to_rs(&mut ctx, t).into_iter()) }, GCompDecl(ci) => { let c = ci.borrow().clone(); @@ -802,7 +750,7 @@ fn tag_dup_decl(gs: &[Global]) -> Vec<Global> { res } -fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> P<ast::Item> { +fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> Vec<P<ast::Item>> { fn mk_item(ctx: &mut GenCtx, name: &str, comment: &str, ty: &Type) -> P<ast::Item> { let rust_name = rust_type_id(ctx, name); let rust_ty = if cty_is_translatable(ty) { @@ -829,7 +777,14 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> P<ast::Item> { }) } - match ty.ty { + if ty.opaque { + return vec![ + mk_opaque_struct(ctx, &ty.name, &ty.layout), + mk_test_fn(ctx, &ty.name, &ty.layout), + ]; + } + + let item = match ty.ty { TComp(ref ci) => { assert!(!ci.borrow().name.is_empty()); mk_item(ctx, &ty.name, &ty.comment, &ty.ty) @@ -839,11 +794,26 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> P<ast::Item> { mk_item(ctx, &ty.name, &ty.comment, &ty.ty) }, _ => mk_item(ctx, &ty.name, &ty.comment, &ty.ty), - } + }; + + vec![item] } fn comp_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>> { + if ci.hide { + return vec![]; + } + + 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), + ]; + } + match ci.kind { CompKind::Struct => cstruct_to_rs(ctx, name, ci), CompKind::Union => cunion_to_rs(ctx, name, ci), @@ -852,9 +822,12 @@ fn comp_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) fn comp_attrs(ctx: &GenCtx, ci: &CompInfo, name: &str, has_destructor: bool, extra: &mut Vec<P<ast::Item>>) -> Vec<ast::Attribute> { let mut attrs = mk_doc_attr(ctx, &ci.comment); - attrs.push(mk_repr_attr(ctx, ci.layout)); + attrs.push(mk_repr_attr(ctx, &ci.layout)); let mut derives = vec![]; + if ci.can_derive_debug() && ctx.options.derive_debug { + derives.push("Debug"); + } if has_destructor { for attr in ctx.options.dtor_attrs.iter() { @@ -862,17 +835,6 @@ fn comp_attrs(ctx: &GenCtx, ci: &CompInfo, name: &str, has_destructor: bool, ext attrs.push(quote_attr!(&ctx.ext_cx, #[$attr])); } } else { - // TODO: make can_derive_debug more reliable in presence of opaque types and all that stuff - let can_derive_debug = ci.members.iter() - .all(|member| match *member { - CompMember::Field(ref f) | - CompMember::CompField(_, ref f) => f.ty.can_derive_debug(), - _ => true - }); - - if can_derive_debug && ctx.options.derive_debug { - derives.push("Debug"); - } derives.push("Copy"); // TODO: make mk_clone_impl work for template arguments, @@ -906,8 +868,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> let mut unnamed: u32 = 0; let mut bitfields: u32 = 0; - if ci.hide || - ci.has_non_type_template_params || + if ci.has_non_type_template_params || template_args.iter().any(|f| f == &TVoid) { return vec!(); } @@ -978,7 +939,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> let vf_name = format!("_vftable_{}", name); let item = P(ast::Item { ident: ctx.ext_cx.ident_of(&vf_name), - attrs: vec!(mk_repr_attr(ctx, layout)), + attrs: vec!(mk_repr_attr(ctx, &layout)), id: ast::DUMMY_NODE_ID, node: ast::ItemKind::Struct( ast::VariantData::Struct(vffields, ast::DUMMY_NODE_ID), @@ -1060,7 +1021,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> 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 || f_ty.is_opaque() { // Be conservative here and assume it might have a // destructor or some other serious constraint. has_destructor = true; @@ -1814,7 +1775,7 @@ fn mk_link_name_attr(ctx: &mut GenCtx, name: String) -> ast::Attribute { respan(ctx.span, attr) } -fn mk_repr_attr(ctx: &GenCtx, layout: Layout) -> ast::Attribute { +fn mk_repr_attr(ctx: &GenCtx, layout: &Layout) -> ast::Attribute { let mut values = vec!(P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("C"))))); if layout.packed { values.push(P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("packed"))))); @@ -2300,7 +2261,6 @@ fn mk_test_fn(ctx: &GenCtx, name: &str, layout: &Layout) -> P<ast::Item> { } fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> P<ast::Item> { - // XXX prevent this spurious clone 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) @@ -2322,7 +2282,7 @@ fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> P<ast::Item> { P(ast::Item { ident: ctx.ext_cx.ident_of(&name), - attrs: vec![mk_repr_attr(ctx, layout.clone())], + attrs: vec![mk_repr_attr(ctx, layout)], id: ast::DUMMY_NODE_ID, node: def, vis: ast::Visibility::Public, @@ -287,6 +287,7 @@ fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<ModuleMap, } } + // TODO: Unify most of these with BindgenOptions? let clang_opts = parser::ClangParserOptions { builtin_names: builtin_names(), builtins: options.builtins, @@ -297,6 +298,8 @@ fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<ModuleMap, enable_cxx_namespaces: options.enable_cxx_namespaces, override_enum_ty: str_to_ikind(&options.override_enum_ty), clang_args: options.clang_args.clone(), + opaque_types: options.opaque_types.clone(), + blacklist_type: options.blacklist_type.clone(), }; parser::parse(clang_opts, logger) diff --git a/src/parser.rs b/src/parser.rs index 0f659d6e..454d8843 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -26,6 +26,8 @@ pub struct ClangParserOptions { pub enable_cxx_namespaces: bool, pub override_enum_ty: Option<il::IKind>, pub clang_args: Vec<String>, + pub opaque_types: Vec<String>, + pub blacklist_type: Vec<String>, } struct ClangParserCtx<'a> { @@ -84,56 +86,40 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { _ => "".to_string() }; let glob_decl = match cursor.kind() { + CXCursor_UnionDecl | + CXCursor_ClassTemplate | + CXCursor_ClassDecl | CXCursor_StructDecl => { - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout))); - GCompDecl(ci) - } - CXCursor_UnionDecl => { - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Union, vec!(), layout))); - GCompDecl(ci) - } - CXCursor_EnumDecl => { - let kind = match override_enum_ty { - Some(t) => t, - None => match cursor.enum_type().kind() { - CXType_SChar | CXType_Char_S => ISChar, - CXType_UChar | CXType_Char_U => IUChar, - CXType_UShort => IUShort, - CXType_UInt => IUInt, - CXType_ULong => IULong, - CXType_ULongLong => IULongLong, - CXType_Short => IShort, - CXType_Int => IInt, - CXType_Long => ILong, - CXType_LongLong => ILongLong, - _ => IInt, - } + let kind = if cursor.kind() == CXCursor_UnionDecl { + CompKind::Union + } else { + CompKind::Struct }; - let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, ctx.current_module_id, filename, kind, vec!(), layout))); - GEnumDecl(ei) - } - CXCursor_ClassTemplate => { - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout))); - GCompDecl(ci) - } - CXCursor_ClassDecl => { + let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling); + let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling); + let mut has_non_type_template_params = false; - let args = match ty.num_template_args() { - -1 => vec!(), - len => { - let mut list = Vec::with_capacity(len as usize); - for i in 0..len { - let arg_type = ty.template_arg_type(i); - if arg_type.kind() != CXType_Invalid { - list.push(conv_ty(ctx, &arg_type, &cursor)); - } else { - has_non_type_template_params = true; - ctx.logger.warn("warning: Template parameter is not a type"); + let args = match cursor.kind() { + CXCursor_ClassDecl => { + match ty.num_template_args() { + -1 => vec![], + len => { + let mut list = Vec::with_capacity(len as usize); + for i in 0..len { + let arg_type = ty.template_arg_type(i); + if arg_type.kind() != CXType_Invalid { + list.push(conv_ty(ctx, &arg_type, &cursor)); + } else { + has_non_type_template_params = true; + ctx.logger.warn("warning: Template parameter is not a type"); + } + } + list } } - list } + _ => vec![], }; let module_id = if args.is_empty() { @@ -154,13 +140,42 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { }) }; - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, module_id, filename, comment, CompKind::Struct, vec!(), layout))); - ci.borrow_mut().args = args; - ci.borrow_mut().has_non_type_template_params = has_non_type_template_params; + let mut ci = CompInfo::new(spelling, module_id, filename, comment, kind, vec![], layout); + ci.opaque = opaque; + ci.hide = hide; + ci.args = args; + ci.has_non_type_template_params = has_non_type_template_params; + + let ci = Rc::new(RefCell::new(ci)); GCompDecl(ci) } + CXCursor_EnumDecl => { + let kind = match override_enum_ty { + Some(t) => t, + None => match cursor.enum_type().kind() { + CXType_SChar | CXType_Char_S => ISChar, + CXType_UChar | CXType_Char_U => IUChar, + CXType_UShort => IUShort, + CXType_UInt => IUInt, + CXType_ULong => IULong, + CXType_ULongLong => IULongLong, + CXType_Short => IShort, + CXType_Int => IInt, + CXType_Long => ILong, + CXType_LongLong => ILongLong, + _ => IInt, + } + }; + + let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, ctx.current_module_id, filename, kind, vec!(), layout))); + GEnumDecl(ei) + } CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => { - let ti = Rc::new(RefCell::new(TypeInfo::new(spelling, ctx.current_module_id, TVoid, layout))); + let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling); + let mut ti = TypeInfo::new(spelling, ctx.current_module_id, TVoid, layout); + ti.opaque = opaque; + + let ti = Rc::new(RefCell::new(ti)); GType(ti) } CXCursor_VarDecl => { @@ -901,12 +916,15 @@ fn visit_top(cursor: &Cursor, let mut ci_ = ci.borrow_mut(); visit_composite(c, p, ctx_, &mut ci_) }); + if anno.opaque { ci.borrow_mut().opaque = true; } + if anno.hide { ci.borrow_mut().hide = true; } + if let Some(other_type_name) = anno.use_as { ci.borrow_mut().name = other_type_name.clone(); ctx_.current_module_mut().translations.insert(other_type_name, GComp(ci)); @@ -1003,6 +1021,11 @@ fn visit_top(cursor: &Cursor, let ti = typedef.typeinfo(); let mut ti = ti.borrow_mut(); ti.ty = ty.clone(); + + if anno.opaque { + ti.opaque = true; + } + ti.comment = cursor.raw_comment(); ctx.current_module_mut().globals.push(typedef); diff --git a/src/types.rs b/src/types.rs index 0578d883..be1f4a5f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,4 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::fmt; use std::rc::Rc; use std::collections::HashMap; @@ -204,20 +204,20 @@ impl Type { pub fn can_derive_debug(&self) -> bool { match *self { - TArray(_, size, _) => size <= 32, - TComp(ref comp) => { - comp.borrow() - .members - .iter() - .all(|member| match *member { - CompMember::Field(ref f) | - CompMember::CompField(_, ref f) => f.ty.can_derive_debug(), - _ => true, - }) - } + 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(), _ => true, } } + + pub fn is_opaque(&self) -> bool { + match *self { + TNamed(ref ti) => ti.borrow().ty.is_opaque(), + TComp(ref ci) => ci.borrow().opaque, + _ => false, + } + } } #[derive(Copy, Clone, Debug, PartialEq)] @@ -321,6 +321,9 @@ pub struct CompInfo { pub has_non_type_template_params: bool, /// If this type was unnamed when parsed pub was_unnamed: bool, + /// Used to detect if we've run in a can_derive_debug cycle while + /// cycling around the template arguments. + detect_derive_debug_cycle: Cell<bool>, } static mut UNNAMED_COUNTER: u32 = 0; @@ -358,6 +361,43 @@ impl CompInfo { typedefs: vec!(), has_non_type_template_params: false, was_unnamed: was_unnamed, + detect_derive_debug_cycle: Cell::new(false), + } + } + + pub fn can_derive_debug(&self) -> bool { + if self.hide || self.opaque { + return false; + } + + if self.detect_derive_debug_cycle.get() { + println!("Derive debug cycle detected: {}!", self.name); + return true; + } + + match self.kind { + CompKind::Union => { + let size_divisor = if self.layout.align == 0 { 1 } else { self.layout.align }; + if self.layout.size / size_divisor > 32 { + return false; + } + + true + } + CompKind::Struct => { + self.detect_derive_debug_cycle.set(true); + + let can_derive_debug = self.args.iter().all(|ty| ty.can_derive_debug()) && + self.members.iter() + .all(|member| match *member { + CompMember::Field(ref f) | + CompMember::CompField(_, ref f) => f.ty.can_derive_debug(), + _ => true, + }); + self.detect_derive_debug_cycle.set(false); + + can_derive_debug + } } } } @@ -448,6 +488,9 @@ pub struct TypeInfo { pub comment: String, pub ty: Type, pub layout: Layout, + // TODO: Is this really useful? + // You can just make opaque the underlying type + pub opaque: bool, } impl TypeInfo { @@ -458,6 +501,7 @@ impl TypeInfo { comment: String::new(), ty: ty, layout: layout, + opaque: false, } } } diff --git a/tests/headers/annotation_hide.hpp b/tests/headers/annotation_hide.hpp index e70ca1f9..3c82c9a2 100644 --- a/tests/headers/annotation_hide.hpp +++ b/tests/headers/annotation_hide.hpp @@ -10,3 +10,7 @@ struct C; struct D { int a; }; + +struct NotAnnotated { + int f; +}; |