summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-08-16 02:21:01 -0500
committerGitHub <noreply@github.com>2016-08-16 02:21:01 -0500
commiteab08be8164bb37ff52bfcb5e739dec58ce9434b (patch)
tree8297a69b9203879ea9a3cb94ad3e83de9a16f121
parent704a6f999904a31d37c1bdc99a66686e65c85cde (diff)
parent52fd1771877b6f8a81b47edc08313f56e50c5d96 (diff)
Auto merge of #29 - emilio:template-unions, r=nox
Add support for basic template unions. Fixes #28. r? @nox cc @bholley
-rw-r--r--src/clang.rs4
-rw-r--r--src/gen.rs390
-rw-r--r--src/parser.rs45
-rw-r--r--src/types.rs106
-rw-r--r--tests/expectations/ref_argument_array.rs27
-rw-r--r--tests/expectations/union_template.rs86
-rw-r--r--tests/expectations/vtable_recursive_sig.rs36
-rw-r--r--tests/headers/ref_argument_array.hpp6
-rw-r--r--tests/headers/union_template.hpp19
-rw-r--r--tests/headers/vtable_recursive_sig.hpp11
10 files changed, 508 insertions, 222 deletions
diff --git a/src/clang.rs b/src/clang.rs
index c230460d..f8a68e12 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -119,6 +119,10 @@ impl Cursor {
}
}
+ pub fn template_kind(&self) -> Enum_CXCursorKind {
+ unsafe { clang_getTemplateCursorKind(self.x) }
+ }
+
pub fn visit<F>(&self, func:F)
where F: for<'a, 'b> FnMut(&'a Cursor, &'b Cursor) -> Enum_CXChildVisitResult
{
diff --git a/src/gen.rs b/src/gen.rs
index 60ea76eb..564e8509 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -69,7 +69,7 @@ fn ref_eq<T>(thing: &T, other: &T) -> bool {
(thing as *const T) == (other as *const T)
}
-fn rust_id(ctx: &mut GenCtx, name: &str) -> (String, bool) {
+fn rust_id(ctx: &GenCtx, name: &str) -> (String, bool) {
let token = parse::token::Ident(ctx.ext_cx.ident_of(name));
if token.is_any_keyword() ||
name.contains("@") ||
@@ -88,7 +88,7 @@ fn rust_id(ctx: &mut GenCtx, name: &str) -> (String, bool) {
}
}
-fn rust_type_id(ctx: &mut GenCtx, name: &str) -> String {
+fn rust_type_id(ctx: &GenCtx, name: &str) -> String {
match name {
"bool" | "uint" | "u8" | "u16" |
"u32" | "f32" | "f64" | "i8" |
@@ -411,7 +411,7 @@ fn gen_global(mut ctx: &mut GenCtx,
!c.args.iter().any(|a| a.name().map(|name| name.is_empty()).unwrap_or(true)) {
defs.extend(comp_to_rs(&mut ctx, &name, c).into_iter());
} else {
- defs.push(opaque_to_rs(&mut ctx, &name, c.layout));
+ defs.push(opaque_to_rs(&mut ctx, &name, c.layout()));
}
},
GComp(ci) => {
@@ -558,7 +558,7 @@ fn gen_globals(mut ctx: &mut GenCtx,
defs
}
-fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)],
+fn mk_extern(ctx: &GenCtx, links: &[(String, LinkType)],
foreign_items: Vec<ast::ForeignItem>,
abi: Abi) -> P<ast::Item> {
let attrs: Vec<_> = links.iter().map(|&(ref l, ref k)| {
@@ -606,7 +606,7 @@ fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)],
})
}
-fn mk_impl(_ctx: &mut GenCtx, ty: P<ast::Ty>,
+fn mk_impl(_ctx: &GenCtx, ty: P<ast::Ty>,
items: Vec<ast::ImplItem>)
-> P<ast::Item> {
aster::AstBuilder::new().item().impl_().with_items(items).build_ty(ty)
@@ -758,7 +758,7 @@ fn tag_dup_decl(gs: &[Global]) -> Vec<Global> {
}
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> {
+ fn mk_item(ctx: &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) {
cty_to_rs(ctx, ty, true, true)
@@ -797,18 +797,25 @@ fn comp_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo)
if ci.opaque {
let name = first(rust_id(ctx, &ci.name));
- return mk_opaque_struct(ctx, &name, &ci.layout);
+ return mk_opaque_struct(ctx, &name, &ci.layout());
}
+ if ci.has_non_type_template_params ||
+ ci.args.iter().any(|f| f == &TVoid) {
+ return vec![];
+ }
+
+ let mut template_args_used = vec![false; ci.args.len()];
+
match ci.kind {
- CompKind::Struct => cstruct_to_rs(ctx, name, ci),
- CompKind::Union => cunion_to_rs(ctx, name, ci),
+ CompKind::Struct => cstruct_to_rs(ctx, name, ci, &mut template_args_used),
+ CompKind::Union => cunion_to_rs(ctx, name, ci, &mut template_args_used),
}
}
fn comp_attrs(ctx: &GenCtx, ci: &CompInfo, name: &str, 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 {
@@ -888,8 +895,34 @@ fn gen_accessors(ctx: &mut GenCtx, name: &str, ty: &ast::Ty, accessor: Accessor,
}
}
-fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>> {
- let layout = ci.layout;
+fn add_extra_template_fields_if_needed(ctx: &GenCtx,
+ template_args: &[Type],
+ template_args_used: &[bool],
+ fields: &mut Vec<ast::StructField>) {
+ let mut phantom_count = 0;
+ for (i, arg) in template_args.iter().enumerate() {
+ if template_args_used[i] {
+ continue;
+ }
+
+ let f_name = format!("_phantom{}", phantom_count);
+ phantom_count += 1;
+ let inner_type = P(cty_to_rs(ctx, &arg, true, false));
+
+ fields.push(ast::StructField {
+ span: ctx.span,
+ ident: Some(ctx.ext_cx.ident_of(&f_name)),
+ vis: ast::Visibility::Public,
+ id: ast::DUMMY_NODE_ID,
+ ty: quote_ty!(&ctx.ext_cx, ::std::marker::PhantomData<$inner_type>),
+ attrs: vec![],
+ });
+ }
+}
+
+fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo,
+ template_args_used: &mut [bool]) -> Vec<P<ast::Item>> {
+ let layout = ci.layout();
let members = &ci.members;
let template_args = &ci.args;
let methodlist = &ci.methods;
@@ -902,11 +935,6 @@ 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.has_non_type_template_params ||
- template_args.iter().any(|f| f == &TVoid) {
- return vec![];
- }
-
let id = rust_type_id(ctx, name);
let id_ty = P(mk_ty(ctx, false, &[id.clone()]));
@@ -989,173 +1017,121 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
let mut anon_enum_count = 0;
let mut setters = vec![];
- let mut template_args_used = vec![false; template_args.len()];
for m in members.iter() {
- if let CompMember::Enum(ref ei) = *m {
- let empty_name = ei.borrow().name.is_empty();
- if empty_name {
- ei.borrow_mut().name = format!("{}_enum{}", name, anon_enum_count);
- anon_enum_count += 1;
- }
-
- let e = ei.borrow().clone();
- extra.extend(cenum_to_rs(ctx, &e.name, e.kind, e.comment, &e.items, e.layout).into_iter());
- continue;
- }
+ match *m {
+ CompMember::Enum(ref ei) => {
+ let empty_name = ei.borrow().name.is_empty();
+ if empty_name {
+ ei.borrow_mut().name = format!("{}_enum{}", name, anon_enum_count);
+ anon_enum_count += 1;
+ }
- fn comp_fields(m: &CompMember)
- -> (Option<Rc<RefCell<CompInfo>>>, Option<FieldInfo>) {
- match *m {
- CompMember::Field(ref f) => { (None, Some(f.clone())) }
- CompMember::Comp(ref rc_c) => { (Some(rc_c.clone()), None) }
- CompMember::CompField(ref rc_c, ref f) => { (Some(rc_c.clone()), Some(f.clone())) }
- _ => unreachable!()
+ let e = ei.borrow().clone();
+ extra.extend(cenum_to_rs(ctx, &e.name, e.kind, e.comment, &e.items, e.layout).into_iter());
}
- }
-
- let (opt_rc_c, opt_f) = comp_fields(m);
+ CompMember::Field(ref f) => {
+ let f_name = match f.bitfields {
+ Some(_) => {
+ bitfields += 1;
+ format!("_bitfield_{}", bitfields)
+ }
+ None => rust_type_id(ctx, &f.name)
+ };
- if let Some(f) = opt_f {
- let f_name = match f.bitfields {
- Some(_) => {
- bitfields += 1;
- format!("_bitfield_{}", bitfields)
+ let is_translatable = cty_is_translatable(&f.ty);
+ if !is_translatable || f.ty.is_opaque() {
+ if !is_translatable {
+ warn!("{}::{} not translatable, void: {}", ci.name, f.name, f.ty == TVoid);
+ }
+ if let Some(layout) = f.ty.layout() {
+ fields.push(mk_blob_field(ctx, &f_name, &layout));
+ }
+ continue;
}
- None => rust_type_id(ctx, &f.name)
- };
- let f_ty = f.ty;
-
- let is_translatable = cty_is_translatable(&f_ty);
- if !is_translatable || f_ty.is_opaque() {
- if !is_translatable {
- warn!("{}::{} not translatable, void: {}", ci.name, f.name, f_ty == TVoid);
- }
- if let Some(layout) = f_ty.layout() {
- fields.push(mk_blob_field(ctx, &f_name, &layout));
+ if ctx.options.gen_bitfield_methods {
+ let mut offset: u32 = 0;
+ if let Some(ref bitfields) = f.bitfields {
+ for &(ref bf_name, bf_size) in bitfields.iter() {
+ setters.extend(gen_bitfield_methods(ctx, &f_name, bf_name, &f.ty, offset as usize, bf_size).into_iter());
+ offset += bf_size;
+ }
+ setters.push(gen_fullbitfield_method(ctx, &f_name, &f.ty, bitfields))
+ }
}
- continue;
- }
- if ctx.options.gen_bitfield_methods {
- let mut offset: u32 = 0;
- if let Some(ref bitfields) = f.bitfields {
- for &(ref bf_name, bf_size) in bitfields.iter() {
- setters.extend(gen_bitfield_methods(ctx, &f_name, bf_name, &f_ty, offset as usize, bf_size).into_iter());
- offset += bf_size;
+ // If the member is not a template argument, it needs the full path.
+ let mut needs_full_path = true;
+ for (index, arg) in template_args.iter().enumerate() {
+ let used = f.ty.signature_contains_type(arg);
+
+ if used {
+ template_args_used[index] = true;
+ needs_full_path = *arg == f.ty || match f.ty {
+ TPtr(ref t, _, _, _) => **t != *arg,
+ TArray(ref t, _, _) => **t != *arg,
+ _ => true,
+ };
+ break;
}
- setters.push(gen_fullbitfield_method(ctx, &f_name, &f_ty, bitfields))
}
- }
- let mut bypass = false;
- let f_ty = if let Some(ref rc_c) = opt_rc_c {
- if rc_c.borrow().members.len() == 1 {
- if let CompMember::Field(ref inner_f) = rc_c.borrow().members[0] {
- bypass = true;
- inner_f.ty.clone()
+ let rust_ty = P(cty_to_rs(ctx, &f.ty, f.bitfields.is_none(), needs_full_path));
+
+ // Wrap mutable fields in a Cell/UnsafeCell
+ let rust_ty = if f.mutable {
+ if !f.ty.can_derive_copy() {
+ quote_ty!(&ctx.ext_cx, ::std::cell::UnsafeCell<$rust_ty>)
+ // We can only wrap in a cell for non-copiable types, since
+ // Cell<T>: Clone, but not Copy.
+ //
+ // It's fine though, since mutating copiable types is trivial
+ // and doesn't make a lot of sense marking fields as `mutable`.
+ } else if !ci.can_derive_copy() {
+ quote_ty!(&ctx.ext_cx, ::std::cell::Cell<$rust_ty>)
} else {
- f_ty
+ rust_ty
}
} else {
- f_ty
- }
- } else {
- f_ty
- };
-
- // If the member is not a template argument, it needs the full path.
- let mut needs_full_path = true;
- for (index, arg) in template_args.iter().enumerate() {
- let used = f_ty.signature_contains_type(arg);
-
- if used {
- template_args_used[index] = true;
- needs_full_path = *arg == f_ty || match f_ty {
- TPtr(ref t, _, _, _) => **t != *arg,
- TArray(ref t, _, _) => **t != *arg,
- _ => true,
- };
- break;
- }
+ rust_ty
+ };
+ let vis = if f.private {
+ ast::Visibility::Inherited
+ } else {
+ ast::Visibility::Public
+ };
+ gen_accessors(ctx, &f_name, &rust_ty, f.accessor, &mut methods);
+ let field = ast::StructField {
+ span: ctx.span,
+ ident: Some(ctx.ext_cx.ident_of(&f_name)),
+ vis: vis,
+ id: ast::DUMMY_NODE_ID,
+ ty: rust_ty,
+ attrs: mk_doc_attr(ctx, &f.comment)
+ };
+ fields.push(field);
}
+ CompMember::Comp(ref rc_c) => {
+ let name_is_empty = rc_c.borrow().name.is_empty();
- let rust_ty = P(cty_to_rs(ctx, &f_ty, f.bitfields.is_none(), needs_full_path));
-
- // Wrap mutable fields in a Cell/UnsafeCell
- let rust_ty = if f.mutable {
- if !f_ty.can_derive_copy() {
- quote_ty!(&ctx.ext_cx, ::std::cell::UnsafeCell<$rust_ty>)
- // We can only wrap in a cell for non-copiable types, since
- // Cell<T>: Clone, but not Copy.
- //
- // It's fine though, since mutating copiable types is trivial
- // and doesn't make a lot of sense marking fields as `mutable`.
- } else if !ci.can_derive_copy() {
- quote_ty!(&ctx.ext_cx, ::std::cell::Cell<$rust_ty>)
+ if name_is_empty {
+ let c = rc_c.borrow();
+ unnamed += 1;
+ let field_name = format!("_bindgen_data_{}_", unnamed);
+ fields.push(mk_blob_field(ctx, &field_name, &c.layout()));
+ methods.extend(gen_comp_methods(ctx, &field_name, 0, c.kind, &c.members, &mut extra).into_iter());
} else {
- rust_ty
+ let name = comp_name(&ctx, rc_c.borrow().kind, &rc_c.borrow().name);
+ extra.extend(comp_to_rs(ctx, &name, rc_c.borrow().clone()).into_iter());
}
- } else {
- rust_ty
- };
- let vis = if f.private {
- ast::Visibility::Inherited
- } else {
- ast::Visibility::Public
- };
- gen_accessors(ctx, &f_name, &rust_ty, f.accessor, &mut methods);
- let field = ast::StructField {
- span: ctx.span,
- ident: Some(ctx.ext_cx.ident_of(&f_name)),
- vis: vis,
- id: ast::DUMMY_NODE_ID,
- ty: rust_ty,
- attrs: mk_doc_attr(ctx, &f.comment)
- };
- fields.push(field);
-
- if bypass {
- continue;
- }
- }
-
- if let Some(rc_c) = opt_rc_c {
- let name_is_empty = rc_c.borrow().name.is_empty();
-
- if name_is_empty {
- let c = rc_c.borrow();
- unnamed += 1;
- let field_name = format!("_bindgen_data_{}_", unnamed);
- fields.push(mk_blob_field(ctx, &field_name, &c.layout));
- methods.extend(gen_comp_methods(ctx, &field_name, 0, c.kind, &c.members, &mut extra).into_iter());
- } else {
- let name = comp_name(&ctx, rc_c.borrow().kind, &rc_c.borrow().name);
- extra.extend(comp_to_rs(ctx, &name, rc_c.borrow().clone()).into_iter());
}
}
}
- let mut phantom_count = 0;
- for (i, arg) in template_args.iter().enumerate() {
- if template_args_used[i] {
- continue;
- }
-
- let f_name = format!("_phantom{}", phantom_count);
- phantom_count += 1;
- let inner_type = P(cty_to_rs(ctx, &arg, true, false));
-
- fields.push(ast::StructField {
- span: ctx.span,
- ident: Some(ctx.ext_cx.ident_of(&f_name)),
- vis: ast::Visibility::Public,
- id: ast::DUMMY_NODE_ID,
- ty: quote_ty!(&ctx.ext_cx, ::std::marker::PhantomData<$inner_type>),
- attrs: vec![],
- });
- }
+ add_extra_template_fields_if_needed(ctx, template_args,
+ template_args_used,
+ &mut fields);
if !setters.is_empty() {
extra.push(mk_impl(ctx, id_ty.clone(), setters));
@@ -1266,15 +1242,16 @@ fn opaque_to_rs(ctx: &mut GenCtx, name: &str, _layout: Layout) -> P<ast::Item> {
quote_item!(&ctx.ext_cx, pub enum $ident {}).unwrap()
}
-fn cunion_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>> {
+fn cunion_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo,
+ template_args_used: &mut [bool]) -> Vec<P<ast::Item>> {
const UNION_DATA_FIELD_NAME: &'static str = "_bindgen_data_";
ctx.saw_union = true;
let members = &ci.members;
- let layout = &ci.layout;
+ let layout = ci.layout();
- fn mk_item(ctx: &mut GenCtx, name: &str, item: ast::ItemKind, vis:
+ fn mk_item(ctx: &GenCtx, name: &str, item: ast::ItemKind, vis:
ast::Visibility, attrs: Vec<ast::Attribute>) -> P<ast::Item> {
P(ast::Item {
ident: ctx.ext_cx.ident_of(name),
@@ -1287,7 +1264,8 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>>
}
let tmp_ci = Rc::new(RefCell::new(ci.clone()));
- let union = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.to_owned(), ROOT_MODULE_ID, TComp(tmp_ci), layout.clone()))));
+ let union = TComp(tmp_ci);
+
// Nested composites may need to emit declarations and implementations as
// they are encountered. The declarations end up in 'extra' and are emitted
@@ -1312,33 +1290,67 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>>
}
}
- let mut fields = members.iter()
- .flat_map(|member| match *member {
- CompMember::Field(ref f) => {
- let cty = cty_to_rs(ctx, &f.ty, false, true);
- Some(mk_union_field(ctx, &f.name, cty))
- }
- _ => None,
- }).collect::<Vec<_>>();
- fields.push(mk_blob_field(ctx, UNION_DATA_FIELD_NAME, layout));
+ let mut fields =
+ members.iter().flat_map(|member| {
+ if let CompMember::Field(ref f) = *member {
+ let mut needs_full_path = true;
+ for (index, arg) in ci.args.iter().enumerate() {
+ let used = f.ty.signature_contains_type(arg);
+
+ if used {
+ template_args_used[index] = true;
+ needs_full_path = *arg == f.ty || match f.ty {
+ TPtr(ref t, _, _, _) => **t != *arg,
+ TArray(ref t, _, _) => **t != *arg,
+ _ => true,
+ };
+ break;
+ }
+ }
+
+ let cty = cty_to_rs(ctx, &f.ty, false, needs_full_path);
+ Some(mk_union_field(ctx, &f.name, cty))
+ } else {
+ None
+ }
+ }).collect::<Vec<_>>();
+
+ fields.push(mk_blob_field(ctx, UNION_DATA_FIELD_NAME, &layout));
+
+ add_extra_template_fields_if_needed(ctx, &ci.args,
+ template_args_used,
+ &mut fields);
+
+ let ty_params = mk_ty_params(ctx, &ci.args);
+
+ let generics = ast::Generics {
+ lifetimes: vec![],
+ ty_params: P::from_vec(ty_params),
+ where_clause: ast::WhereClause {
+ id: ast::DUMMY_NODE_ID,
+ predicates: vec![]
+ }
+ };
// TODO: use aster here.
let def = ast::ItemKind::Struct(
ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID),
- ast::Generics::default()
+ generics.clone()
);
let union_id = rust_type_id(ctx, name);
let union_attrs = comp_attrs(&ctx, &ci, name, &mut extra);
- extra.push(mk_test_fn(ctx, &name, &layout));
+ if ci.args.is_empty() {
+ extra.push(mk_test_fn(ctx, &name, &layout));
+ }
let union_def = mk_item(ctx, &union_id, def, ast::Visibility::Public, union_attrs);
let union_impl = ast::ItemKind::Impl(
ast::Unsafety::Normal,
ast::ImplPolarity::Positive,
- ast::Generics::default(),
+ generics,
None,
P(cty_to_rs(ctx, &union, true, true)),
gen_comp_methods(ctx, UNION_DATA_FIELD_NAME, 0, CompKind::Union, &members, &mut extra),
@@ -1551,17 +1563,7 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
let c = rc_c.borrow();
let name = comp_name(&ctx, c.kind, &c.name);
extra.extend(comp_to_rs(ctx, &name, c.clone()).into_iter());
- c.layout.size
- }
- CompMember::CompField(ref rc_c, ref f) => {
- if ctx.options.gen_bitfield_methods {
- methods.extend(mk_field_method(ctx, f, offset).into_iter());
- }
-
- let c = rc_c.borrow();
- let name = comp_name(&ctx, c.kind, &c.name);
- extra.extend(comp_to_rs(ctx, &name, c.clone()).into_iter());
- f.ty.size()
+ c.layout().size
}
CompMember::Enum(_) => 0
};
@@ -1751,7 +1753,7 @@ fn mk_blob_field(ctx: &GenCtx, name: &str, layout: &Layout) -> ast::StructField
}
}
-fn mk_link_name_attr(ctx: &mut GenCtx, name: String) -> ast::Attribute {
+fn mk_link_name_attr(ctx: &GenCtx, name: String) -> ast::Attribute {
let lit = respan(ctx.span, ast::LitKind::Str(intern(&name).as_str(), ast::StrStyle::Cooked));
let attr_val = P(respan(ctx.span, ast::MetaItemKind::NameValue(
InternedString::new("link_name"), lit
@@ -1859,7 +1861,7 @@ fn cvar_to_rs(ctx: &mut GenCtx, name: String,
}
}
-fn cfuncty_to_rs(ctx: &mut GenCtx,
+fn cfuncty_to_rs(ctx: &GenCtx,
rty: &Type,
aty: &[(String, Type)],
var: bool) -> ast::FnDecl {
@@ -1949,7 +1951,7 @@ fn cfunc_to_rs(ctx: &mut GenCtx,
}
}
-fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool, use_full_path: bool) -> ast::Ty {
+fn cty_to_rs(ctx: &GenCtx, ty: &Type, allow_bool: bool, use_full_path: bool) -> ast::Ty {
let prefix = vec!["std".to_owned(), "os".to_owned(), "raw".to_owned()];
let raw = |fragment: &str| {
let mut path = prefix.clone();
@@ -2088,7 +2090,7 @@ fn mk_ty_args(ctx: &GenCtx, global: bool, segments: &[String], args: Vec<P<ast::
}
}
-fn mk_ptrty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty {
+fn mk_ptrty(ctx: &GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty {
let ty = ast::TyKind::Ptr(ast::MutTy {
ty: P(base.clone()),
mutbl: if is_const { ast::Mutability::Immutable } else { ast::Mutability::Mutable }
@@ -2138,7 +2140,7 @@ fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty {
}
}
-fn mk_fn_proto_ty(ctx: &mut GenCtx,
+fn mk_fn_proto_ty(ctx: &GenCtx,
decl: &ast::FnDecl,
abi: Abi) -> ast::Ty {
let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
@@ -2155,7 +2157,7 @@ fn mk_fn_proto_ty(ctx: &mut GenCtx,
}
}
-fn mk_fnty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: Abi) -> ast::Ty {
+fn mk_fnty(ctx: &GenCtx, decl: &ast::FnDecl, abi: Abi) -> ast::Ty {
let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
unsafety: ast::Unsafety::Unsafe,
abi: abi,
diff --git a/src/parser.rs b/src/parser.rs
index df6dbf55..49d62b81 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -113,7 +113,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
let comment = cursor.raw_comment();
let (file, _, _, _) = cursor.location().location();
let ty = cursor.cur_type();
- let layout = Layout::new(ty.size(), ty.align());
+ let layout = Layout::from_ty(&ty);
let filename = match Path::new(&file.name().unwrap_or("".to_owned())).file_name() {
Some(name) => name.to_string_lossy().replace(".", "_"),
_ => "".to_string()
@@ -124,10 +124,16 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
CXCursor_ClassDecl |
CXCursor_StructDecl => {
let anno = Annotations::new(&cursor);
- let kind = if cursor.kind() == CXCursor_UnionDecl {
- CompKind::Union
- } else {
- CompKind::Struct
+
+ let kind = match cursor.kind() {
+ CXCursor_UnionDecl => CompKind::Union,
+ CXCursor_ClassTemplate => {
+ match cursor.template_kind() {
+ CXCursor_UnionDecl => CompKind::Union,
+ _ => CompKind::Struct,
+ }
+ }
+ _ => CompKind::Struct,
};
let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling);
@@ -161,7 +167,9 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
}
};
- let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout, anno);
+ let mut ci = CompInfo::new(spelling, ctx.current_module_id,
+ filename, comment, kind, vec![],
+ layout, anno);
ci.parser_cursor = Some(cursor);
// If it's an instantiation of another template,
@@ -332,8 +340,9 @@ fn mk_fn_sig_resolving_typedefs(ctx: &mut ClangParserCtx,
// get parameter names and types.
cursor.args().iter().map(|arg| {
let arg_name = arg.spelling();
- let is_class_typedef = arg.cur_type().sanitized_spelling_in(typedefs);
- (arg_name, conv_ty_resolving_typedefs(ctx, &arg.cur_type(), arg, is_class_typedef))
+ let arg_ty = arg.cur_type();
+ let is_class_typedef = arg_ty.sanitized_spelling_in(typedefs);
+ (arg_name, conv_ty_resolving_typedefs(ctx, &arg_ty, arg, is_class_typedef))
}).collect()
}
_ => {
@@ -387,7 +396,7 @@ fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx,
// If the cursor kind is CXCursor_ClassTemplate, this will still return -1
// and we'll have to keep traversing the cursor.
let args = match ty.num_template_args() {
- -1 => vec!(),
+ -1 => vec![],
len => {
let mut list = Vec::with_capacity(len as usize);
for i in 0..len {
@@ -442,8 +451,14 @@ fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx,
TNamed(ti)
}
CXCursor_NoDeclFound => {
- let layout = Layout::new(ty.size(), ty.align());
- TNamed(Rc::new(RefCell::new(TypeInfo::new(ty.spelling().replace("const ", ""), ctx.current_module_id, TVoid, layout))))
+ let canonical = ty.canonical_type();
+ let kind = canonical.kind();
+ if kind != CXType_Invalid && kind != CXType_Unexposed {
+ conv_ty_resolving_typedefs(ctx, &canonical, &ty_decl, resolve_typedefs)
+ } else {
+ let layout = Layout::from_ty(ty);
+ TNamed(Rc::new(RefCell::new(TypeInfo::new(ty.spelling().replace("const ", ""), ctx.current_module_id, TVoid, layout))))
+ }
}
_ => {
let fail = ctx.options.fail_on_unknown_type;
@@ -468,7 +483,7 @@ fn conv_ty_resolving_typedefs(ctx: &mut ClangParserCtx,
ty: &cx::Type,
cursor: &Cursor,
resolve_typedefs: bool) -> il::Type {
- let layout = Layout::new(ty.size(), ty.align());
+ let layout = Layout::from_ty(&ty);
// println!("conv_ty: `{}` layout: {:?}, kind {}: {}", cursor.spelling(), layout, ty.kind(), type_to_str(ty.kind()));
match ty.kind() {
@@ -877,7 +892,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
});
}
CXCursor_PackedAttr => {
- ci.layout.packed = true;
+ ci.set_packed(true);
}
CXCursor_TemplateTypeParameter => {
ci.args.push(conv_template_type_parameter(ctx, cursor));
@@ -979,8 +994,8 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
}
}
for base in ci.members[..ci.base_members].iter() {
- let base = match base {
- &CompMember::Field(ref fi) => {
+ let base = match *base {
+ CompMember::Field(ref fi) => {
match fi.ty {
TComp(ref ci) => ci.clone(),
_ => continue,
diff --git a/src/types.rs b/src/types.rs
index 09ce4cb2..30a4f454 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -11,7 +11,7 @@ pub use self::Global::*;
pub use self::Type::*;
pub use self::IKind::*;
pub use self::FKind::*;
-use clang::Cursor;
+use clang::{self, Cursor};
use parser::{Annotations, Accessor};
@@ -167,7 +167,8 @@ pub struct FuncSig {
pub abi: abi::Abi,
}
-#[derive(Clone, PartialEq, Debug)]
+// NOTE: Remember to add your new variant to the PartialEq implementation below!
+#[derive(Clone, Debug)]
pub enum Type {
TVoid,
TInt(IKind, Layout),
@@ -181,6 +182,41 @@ pub enum Type {
TEnum(Rc<RefCell<EnumInfo>>)
}
+/// Compares to Rc<T> types looking first at the value they point to.
+///
+/// This is needed to avoid infinite recursion in things like virtual function
+/// signatures.
+fn ref_ptr_aware_eq<T: PartialEq>(one: &Rc<T>, other: &Rc<T>) -> bool {
+ &**one as *const T == &**other as *const T ||
+ **one == **other
+}
+
+impl PartialEq for Type {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (&TVoid, &TVoid)
+ => true,
+ (&TInt(ref kind, ref l), &TInt(ref o_kind, ref o_l))
+ => kind == o_kind && l == o_l,
+ (&TFloat(ref kind, ref l), &TFloat(ref o_kind, ref o_l))
+ => kind == o_kind && l == o_l,
+ (&TPtr(ref ty, is_const, is_ref, ref l), &TPtr(ref o_ty, o_is_const, o_is_ref, ref o_l))
+ => is_const == o_is_const && is_ref == o_is_ref && l == o_l && ty == o_ty,
+ (&TArray(ref ty, count, ref l), &TArray(ref o_ty, o_count, ref o_l))
+ => count == o_count && l == o_l && ty == o_ty,
+ (&TFuncProto(ref sig), &TFuncProto(ref o_sig))
+ => sig == o_sig,
+ (&TNamed(ref ti), &TNamed(ref o_ti))
+ => ref_ptr_aware_eq(ti, o_ti),
+ (&TComp(ref ci), &TComp(ref o_ci))
+ => ref_ptr_aware_eq(ci, o_ci),
+ (&TEnum(ref ei), &TEnum(ref o_ei))
+ => ref_ptr_aware_eq(ei, o_ei),
+ _ => false,
+ }
+ }
+}
+
impl Type {
#[allow(dead_code)]
pub fn name(&self) -> Option<String> {
@@ -226,7 +262,6 @@ impl Type {
self.layout().map(|l| l.size).unwrap_or(0)
}
- #[allow(dead_code)]
pub fn align(&self) -> usize {
self.layout().map(|l| l.align).unwrap_or(0)
}
@@ -344,13 +379,22 @@ pub struct Layout {
}
impl Layout {
- pub fn new(size: usize, align: usize) -> Layout {
+ pub fn new(size: usize, align: usize) -> Self {
Layout { size: size, align: align, packed: false }
}
+ // TODO: make this fallible using fallible_size().
+ pub fn from_ty(ty: &clang::Type) -> Self {
+ Self::new(ty.size(), ty.align())
+ }
+
pub fn zero() -> Layout {
Layout { size: 0, align: 0, packed: false }
}
+
+ pub fn is_zero(&self) -> bool {
+ *self == Self::zero()
+ }
}
#[derive(Debug, Copy, Clone, PartialEq)]
@@ -397,8 +441,6 @@ pub enum FKind {
pub enum CompMember {
Field(FieldInfo),
Comp(Rc<RefCell<CompInfo>>),
- #[allow(dead_code)]
- CompField(Rc<RefCell<CompInfo>>, FieldInfo),
Enum(Rc<RefCell<EnumInfo>>),
}
@@ -431,7 +473,7 @@ pub struct CompInfo {
/// the correct layout.
pub opaque: bool,
pub base_members: usize,
- pub layout: Layout,
+ layout: Layout,
/// If this struct is explicitely marked as non-copiable.
pub no_copy: bool,
/// Typedef'd types names, that we'll resolve early to avoid name conflicts
@@ -504,6 +546,47 @@ impl CompInfo {
}
}
+ // Gets or computes the layout as appropriately.
+ pub fn layout(&self) -> Layout {
+ use std::cmp;
+ // The returned layout from clang is zero as of right now, but we should
+ // change it to be fallible to distinguish correctly between zero-sized
+ // types and unknown layout.
+ if !self.layout.is_zero() {
+ return self.layout.clone();
+ }
+
+ if self.args.is_empty() {
+ return self.layout.clone();
+ }
+
+ if self.kind == CompKind::Struct {
+ return self.layout.clone();
+ }
+
+ // If we're a union without known layout, we try to compute it from our
+ // members. This is not ideal, but clang fails to report the size for
+ // these kind of unions, see test/headers/template_union.hpp
+ let mut max_size = 0;
+ let mut max_align = 0;
+ for member in &self.members {
+ let layout = match *member {
+ CompMember::Field(ref f) => f.ty.layout().unwrap_or(Layout::zero()),
+ CompMember::Comp(ref ci) => ci.borrow().layout(),
+ CompMember::Enum(ref ei) => ei.borrow().layout.clone(),
+ };
+
+ max_size = cmp::max(max_size, layout.size);
+ max_align = cmp::max(max_align, layout.align);
+ }
+
+ Layout::new(max_size, max_align)
+ }
+
+ pub fn set_packed(&mut self, packed: bool) {
+ self.layout.packed = packed
+ }
+
// Return the module id or the class declaration module id.
pub fn module_id(&self) -> ModuleId {
self.ref_template.as_ref().and_then(|t| if let TComp(ref ci) = *t {
@@ -538,8 +621,7 @@ impl CompInfo {
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(),
+ CompMember::Field(ref f) => f.ty.can_derive_debug(),
_ => true,
});
self.detect_derive_debug_cycle.set(false);
@@ -577,8 +659,7 @@ impl CompInfo {
self.ref_template.as_ref().map_or(false, |t| t.has_destructor()) ||
self.args.iter().any(|t| t.has_destructor()) ||
self.members.iter().enumerate().any(|(index, m)| match *m {
- CompMember::Field(ref f) |
- CompMember::CompField(_, ref f) => {
+ CompMember::Field(ref f) => {
// Base members may not be resolved yet
if index < self.base_members {
f.ty.has_destructor()
@@ -611,8 +692,7 @@ impl CompInfo {
// since copyability depends on the types itself.
self.ref_template.as_ref().map_or(true, |t| t.can_derive_copy()) &&
self.members.iter().all(|m| match *m {
- CompMember::Field(ref f) |
- CompMember::CompField(_, ref f) => f.ty.can_derive_copy(),
+ CompMember::Field(ref f) => f.ty.can_derive_copy(),
_ => true,
})
}
diff --git a/tests/expectations/ref_argument_array.rs b/tests/expectations/ref_argument_array.rs
new file mode 100644
index 00000000..9660fbf2
--- /dev/null
+++ b/tests/expectations/ref_argument_array.rs
@@ -0,0 +1,27 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub const NSID_LENGTH: ::std::os::raw::c_uint = 10;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_nsID {
+ pub _vftable: *const _vftable_Struct_nsID,
+}
+#[repr(C)]
+pub struct _vftable_Struct_nsID {
+ pub ToProvidedString: unsafe extern "C" fn(this:
+ *mut ::std::os::raw::c_void,
+ aDest:
+ *mut [::std::os::raw::c_char; 10usize]),
+}
+impl ::std::clone::Clone for Struct_nsID {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_nsID() {
+ assert_eq!(::std::mem::size_of::<Struct_nsID>() , 8usize);
+ assert_eq!(::std::mem::align_of::<Struct_nsID>() , 8usize);
+}
diff --git a/tests/expectations/union_template.rs b/tests/expectations/union_template.rs
new file mode 100644
index 00000000..eb6705f0
--- /dev/null
+++ b/tests/expectations/union_template.rs
@@ -0,0 +1,86 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[derive(Copy, Debug)]
+#[repr(C)]
+pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
+impl <T> __BindgenUnionField<T> {
+ #[inline]
+ pub fn new() -> Self { __BindgenUnionField(::std::marker::PhantomData) }
+ #[inline]
+ pub unsafe fn as_ref(&self) -> &T { ::std::mem::transmute(self) }
+ #[inline]
+ pub unsafe fn as_mut(&mut self) -> &mut T { ::std::mem::transmute(self) }
+}
+impl <T> ::std::default::Default for __BindgenUnionField<T> {
+ #[inline]
+ fn default() -> Self { Self::new() }
+}
+impl <T> ::std::clone::Clone for __BindgenUnionField<T> {
+ #[inline]
+ fn clone(&self) -> Self { Self::new() }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Struct_NastyStruct<T> {
+ pub mIsSome: bool,
+ pub mStorage: Union_NastyStruct_union_template_hpp_unnamed_1<T>,
+ pub NastyStruct_union_template_hpp_unnamed_2: Union_NastyStruct_union_template_hpp_unnamed_2<T>,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Union_NastyStruct_union_template_hpp_unnamed_1<T> {
+ pub mFoo: __BindgenUnionField<*mut ::std::os::raw::c_void>,
+ pub mDummy: __BindgenUnionField<::std::os::raw::c_ulong>,
+ pub _bindgen_data_: u64,
+ pub _phantom0: ::std::marker::PhantomData<T>,
+}
+impl <T> Union_NastyStruct_union_template_hpp_unnamed_1<T> {
+ pub unsafe fn mFoo(&mut self) -> *mut *mut ::std::os::raw::c_void {
+ let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
+ ::std::mem::transmute(raw.offset(0))
+ }
+ pub unsafe fn mDummy(&mut self) -> *mut ::std::os::raw::c_ulong {
+ let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
+ ::std::mem::transmute(raw.offset(0))
+ }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Union_NastyStruct_union_template_hpp_unnamed_2<T> {
+ pub wat: __BindgenUnionField<::std::os::raw::c_short>,
+ pub wut: __BindgenUnionField<*mut ::std::os::raw::c_int>,
+ pub _bindgen_data_: u64,
+ pub _phantom0: ::std::marker::PhantomData<T>,
+}
+impl <T> Union_NastyStruct_union_template_hpp_unnamed_2<T> {
+ pub unsafe fn wat(&mut self) -> *mut ::std::os::raw::c_short {
+ let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
+ ::std::mem::transmute(raw.offset(0))
+ }
+ pub unsafe fn wut(&mut self) -> *mut *mut ::std::os::raw::c_int {
+ let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
+ ::std::mem::transmute(raw.offset(0))
+ }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Union_Whatever<T> {
+ pub mTPtr: __BindgenUnionField<*mut ::std::os::raw::c_void>,
+ pub mInt: __BindgenUnionField<::std::os::raw::c_int>,
+ pub _bindgen_data_: u64,
+ pub _phantom0: ::std::marker::PhantomData<T>,
+}
+impl <T> Union_Whatever<T> {
+ pub unsafe fn mTPtr(&mut self) -> *mut *mut ::std::os::raw::c_void {
+ let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
+ ::std::mem::transmute(raw.offset(0))
+ }
+ pub unsafe fn mInt(&mut self) -> *mut ::std::os::raw::c_int {
+ let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
+ ::std::mem::transmute(raw.offset(0))
+ }
+}
diff --git a/tests/expectations/vtable_recursive_sig.rs b/tests/expectations/vtable_recursive_sig.rs
new file mode 100644
index 00000000..8f972e92
--- /dev/null
+++ b/tests/expectations/vtable_recursive_sig.rs
@@ -0,0 +1,36 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Base {
+ pub _vftable: *const _vftable_Base,
+}
+#[repr(C)]
+pub struct _vftable_Base {
+ pub AsDerived: unsafe extern "C" fn(this: *mut ::std::os::raw::c_void)
+ -> *mut Derived,
+}
+impl ::std::clone::Clone for Base {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Base() {
+ assert_eq!(::std::mem::size_of::<Base>() , 8usize);
+ assert_eq!(::std::mem::align_of::<Base>() , 8usize);
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Derived {
+ pub _base: Base,
+}
+#[repr(C)]
+pub struct _vftable_Derived {
+ pub _base: _vftable_Base,
+}
+impl ::std::clone::Clone for Derived {
+ fn clone(&self) -> Self { *self }
+}
diff --git a/tests/headers/ref_argument_array.hpp b/tests/headers/ref_argument_array.hpp
new file mode 100644
index 00000000..dc73fd62
--- /dev/null
+++ b/tests/headers/ref_argument_array.hpp
@@ -0,0 +1,6 @@
+
+#define NSID_LENGTH 10
+class nsID {
+public:
+ virtual void ToProvidedString(char (&aDest)[NSID_LENGTH]) = 0;
+};
diff --git a/tests/headers/union_template.hpp b/tests/headers/union_template.hpp
new file mode 100644
index 00000000..0d0a9bb3
--- /dev/null
+++ b/tests/headers/union_template.hpp
@@ -0,0 +1,19 @@
+template<typename T>
+struct NastyStruct {
+ bool mIsSome;
+ union {
+ void* mFoo;
+ unsigned long mDummy;
+ } mStorage;
+
+ union {
+ short wat;
+ int* wut;
+ };
+};
+
+template<typename T>
+union Whatever {
+ void* mTPtr;
+ int mInt;
+};
diff --git a/tests/headers/vtable_recursive_sig.hpp b/tests/headers/vtable_recursive_sig.hpp
new file mode 100644
index 00000000..4e5af806
--- /dev/null
+++ b/tests/headers/vtable_recursive_sig.hpp
@@ -0,0 +1,11 @@
+// bindgen-flags: -std=c++11 -no-type-renaming
+
+class Derived;
+class Base {
+public:
+ virtual Derived* AsDerived() { return nullptr; }
+};
+
+class Derived final : public Base {
+ virtual Derived* AsDerived() override { return this; }
+};