summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gen.rs110
-rw-r--r--src/lib.rs3
-rw-r--r--src/parser.rs117
-rw-r--r--src/types.rs68
-rw-r--r--tests/headers/annotation_hide.hpp4
5 files changed, 168 insertions, 134 deletions
diff --git a/src/gen.rs b/src/gen.rs
index 894bf3f8..3d1202d2 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -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,
diff --git a/src/lib.rs b/src/lib.rs
index 3bcc4ca0..3397ffb4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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;
+};