diff options
48 files changed, 1221 insertions, 327 deletions
@@ -14,7 +14,7 @@ build = "build.rs" clippy = { version = "*", optional = true } log = "0.3.*" libc = "0.2.*" -syntex_syntax = "0.29.*" +syntex_syntax = "0.32" [features] static = [] diff --git a/src/clang.rs b/src/clang.rs index d60de336..9c46a94e 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -25,6 +25,12 @@ impl Cursor { } } + pub fn display_name(&self) -> String { + unsafe { + String_ { x: clang_getCursorDisplayName(self.x) }.to_string() + } + } + pub fn mangling(&self) -> String { let mut mangling = unsafe { String_ { x: clang_Cursor_getMangling(self.x) }.to_string() @@ -37,6 +43,12 @@ impl Cursor { mangling } + pub fn lexical_parent(&self) -> Cursor { + unsafe { + Cursor { x: clang_getCursorLexicalParent(self.x) } + } + } + pub fn semantic_parent(&self) -> Cursor { unsafe { Cursor { x: clang_getCursorSemanticParent(self.x) } @@ -203,6 +215,12 @@ impl Cursor { } } + pub fn is_mutable_field(&self) -> bool { + unsafe { + clang_CXXField_isMutable(self.x) != 0 + } + } + // CXX method pub fn method_is_static(&self) -> bool { unsafe { @@ -272,6 +290,30 @@ pub struct Type { x: CXType } +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum LayoutError { + Invalid, + Incomplete, + Dependent, + NotConstantSize, + InvalidFieldName, + Unknown, +} + +impl ::std::convert::From<i32> for LayoutError { + fn from(val: i32) -> Self { + use self::LayoutError::*; + match val { + CXTypeLayoutError_Invalid => Invalid, + CXTypeLayoutError_Incomplete => Incomplete, + CXTypeLayoutError_Dependent => Dependent, + CXTypeLayoutError_NotConstantSize => NotConstantSize, + CXTypeLayoutError_InvalidFieldName => InvalidFieldName, + _ => Unknown, + } + } +} + impl Type { // common pub fn kind(&self) -> Enum_CXTypeKind { @@ -290,6 +332,7 @@ impl Type { } } + // XXX make it more consistent // // This is currently only used to detect typedefs, @@ -319,6 +362,15 @@ impl Type { } } + pub fn fallible_size(&self) -> Result<usize, LayoutError> { + let val = unsafe { clang_Type_getSizeOf(self.x) }; + if val < 0 { + Err(LayoutError::from(val as i32)) + } else { + Ok(val as usize) + } + } + pub fn align(&self) -> usize { unsafe { let val = clang_Type_getAlignOf(self.x); diff --git a/src/clangll.rs b/src/clangll.rs index 4d2ae32d..4877ea70 100644 --- a/src/clangll.rs +++ b/src/clangll.rs @@ -1236,6 +1236,7 @@ extern "C" { pub fn clang_CXXMethod_isPureVirtual(C: CXCursor) -> c_uint; pub fn clang_CXXMethod_isStatic(C: CXCursor) -> c_uint; pub fn clang_CXXMethod_isVirtual(C: CXCursor) -> c_uint; + pub fn clang_CXXField_isMutable(C: CXCursor) -> c_uint; pub fn clang_getTemplateCursorKind(C: CXCursor) -> Enum_CXCursorKind; pub fn clang_getSpecializedCursorTemplate(C: CXCursor) -> CXCursor; pub fn clang_getCursorReferenceNameRange(C: CXCursor, @@ -1,18 +1,16 @@ use std; -use std::cmp; use std::cell::RefCell; use std::vec::Vec; use std::rc::Rc; use std::collections::HashMap; use syntax::abi::Abi; use syntax::ast; -use syntax::codemap::{Span, Spanned, respan, ExpnInfo, NameAndSpan, MacroBang}; +use syntax::codemap::{Span, respan, ExpnInfo, NameAndSpan, MacroBang}; use syntax::ext::base; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; use syntax::ext::quote::rt::ToTokens; use syntax::feature_gate::Features; -use syntax::owned_slice::OwnedSlice; use syntax::parse; use syntax::parse::token::{InternedString, intern}; use syntax::attr::mk_attr_id; @@ -71,17 +69,17 @@ fn ref_eq<T>(thing: &T, other: &T) -> bool { fn empty_generics() -> ast::Generics { ast::Generics { - lifetimes: Vec::new(), - ty_params: OwnedSlice::empty(), + lifetimes: vec![], + ty_params: P::new(), where_clause: ast::WhereClause { id: ast::DUMMY_NODE_ID, - predicates: Vec::new() + predicates: vec![] } } } fn rust_id(ctx: &mut GenCtx, name: &str) -> (String, bool) { - let token = parse::token::Ident(ctx.ext_cx.ident_of(name), parse::token::Plain); + let token = parse::token::Ident(ctx.ext_cx.ident_of(name)); if token.is_any_keyword() || "bool" == name { let mut s = name.to_owned(); s.push_str("_"); @@ -155,7 +153,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, self_kind: ast::SelfKind) -> ast::ImplItem { let fndecl; - let mut args = vec!(); + let mut args = vec![]; match self_kind { ast::SelfKind::Static => (), @@ -217,7 +215,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, }; let block = ast::Block { - stmts: vec!(), + stmts: vec![], expr: Some(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Call( @@ -272,6 +270,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, vis: ast::Visibility::Public, attrs: attrs, node: ast::ImplItemKind::Method(sig, P(block)), + defaultness: ast::Defaultness::Final, span: ctx.span } } @@ -282,7 +281,7 @@ pub fn gen_mods(links: &[(String, LinkType)], span: Span) -> Vec<P<ast::Item>> { // Create a dummy ExtCtxt. We only need this for string interning and that uses TLS. let mut features = Features::new(); - features.allow_quote = true; + features.quote = true; let cfg = ExpansionConfig { crate_name: "xxx".to_owned(), features: Some(&features), @@ -292,7 +291,7 @@ pub fn gen_mods(links: &[(String, LinkType)], let sess = &parse::ParseSess::new(); let mut feature_gated_cfgs = vec![]; let mut ctx = GenCtx { - ext_cx: base::ExtCtxt::new(sess, Vec::new(), cfg, &mut feature_gated_cfgs), + ext_cx: base::ExtCtxt::new(sess, vec![], cfg, &mut feature_gated_cfgs), options: options, span: span, module_map: map, @@ -385,10 +384,21 @@ fn gen_global(mut ctx: &mut GenCtx, defs.extend(ctypedef_to_rs(&mut ctx, t).into_iter()) }, GCompDecl(ci) => { - let c = ci.borrow().clone(); + let mut c = ci.borrow().clone(); let name = comp_name(&ctx, c.kind, &c.name); - - defs.push(opaque_to_rs(&mut ctx, &name, c.layout)); + // Use the reference template if any + while let Some(TComp(ref_template)) = c.ref_template.clone() { + if c.name != ref_template.borrow().name { + break; + } + c = ref_template.borrow().clone(); + } + if !c.args.is_empty() && + !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)); + } }, GComp(ci) => { let c = ci.borrow().clone(); @@ -421,9 +431,9 @@ fn gen_globals(mut ctx: &mut GenCtx, globs: &[Global]) -> Vec<P<ast::Item>> { let uniq_globs = tag_dup_decl(globs); - let mut fs = vec!(); - let mut vs = vec!(); - let mut gs = vec!(); + let mut fs = vec![]; + let mut vs = vec![]; + let mut gs = vec![]; for g in uniq_globs.into_iter() { match g { GOther => {} @@ -448,7 +458,7 @@ fn gen_globals(mut ctx: &mut GenCtx, } } - let mut defs = vec!(); + let mut defs = vec![]; gs = remove_redundant_decl(gs); for mut g in gs.into_iter() { @@ -566,7 +576,7 @@ fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)], }) }).collect(); - let mut items = Vec::new(); + let mut items = vec![]; items.extend(foreign_items.into_iter()); let ext = ast::ItemKind::ForeignMod(ast::ForeignMod { abi: abi, @@ -597,7 +607,7 @@ fn mk_impl(ctx: &mut GenCtx, ty: P<ast::Ty>, P(ast::Item { ident: ctx.ext_cx.ident_of(""), - attrs: vec!(), + attrs: vec![], id: ast::DUMMY_NODE_ID, node: ext, vis: ast::Visibility::Inherited, @@ -704,7 +714,7 @@ fn tag_dup_decl(gs: &[Global]) -> Vec<Global> { return vec![]; } - let mut step: Vec<Global> = vec!(); + let mut step: Vec<Global> = vec![]; step.push(gs[0].clone()); for (i, _gsi) in gs.iter().enumerate().skip(1) { @@ -724,7 +734,7 @@ fn tag_dup_decl(gs: &[Global]) -> Vec<Global> { } let len = step.len(); - let mut res: Vec<Global> = vec!(); + let mut res: Vec<Global> = vec![]; for i in 0..len { let mut dup = false; match &step[i] { @@ -854,53 +864,46 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> let members = &ci.members; let template_args = &ci.args; let methodlist = &ci.methods; - let mut fields = vec!(); - let mut methods = vec!(); + let mut fields = vec![]; + let mut methods = vec![]; // Nested composites may need to emit declarations and implementations as // they are encountered. The declarations end up in 'extra' and are emitted // after the current struct. - let mut extra = vec!(); + let mut extra = vec![]; 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!(); + return vec![]; } let id = rust_type_id(ctx, name); let id_ty = P(mk_ty(ctx, false, &[id.clone()])); if ci.has_vtable { - let mut vffields = vec!(); - let base_vftable = if !members.is_empty() { - if let CompMember::Field(ref fi) = members[0] { - match fi.ty { - TComp(ref ci2) => { - let ci2 = ci2.borrow(); - if ci2.has_vtable { - Some(format!("_vftable_{}", ci2.name)) - } else { - None - } - }, - _ => None + let mut vffields = vec![]; + let base_vftable = match members.get(0) { + Some(&CompMember::Field(FieldInfo { ty: TComp(ref ci2), .. })) => { + let ci2 = ci2.borrow(); + if ci2.has_vtable { + Some(format!("_vftable_{}", ci2.name)) + } else { + None } - } else { - None - } - } else { - None + }, + _ => None, }; if let Some(ref base) = base_vftable { - let field = ast::StructField_ { - kind: ast::NamedField(ctx.ext_cx.ident_of("_base"), ast::Visibility::Public), + vffields.push(ast::StructField { + span: ctx.span, + vis: ast::Visibility::Public, + ident: Some(ctx.ext_cx.ident_of("_base")), id: ast::DUMMY_NODE_ID, ty: P(mk_ty(ctx, false, &[base.clone()])), - attrs: vec!(), - }; - vffields.push(respan(ctx.span, field)); + attrs: vec![], + }); } for vm in ci.vmethods.iter() { @@ -914,13 +917,14 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> let name = first(rust_id(ctx, &vm.name)); - let field = ast::StructField_ { - kind: ast::NamedField(ctx.ext_cx.ident_of(&name), ast::Visibility::Public), + vffields.push(ast::StructField { + span: ctx.span, + vis: ast::Visibility::Public, + ident: Some(ctx.ext_cx.ident_of(&name)), id: ast::DUMMY_NODE_ID, ty: P(ty), - attrs: vec!(), - }; - vffields.push(respan(ctx.span, field)); + attrs: vec![], + }); } // FIXME: rustc actually generates tons of warnings @@ -947,17 +951,19 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> if base_vftable.is_none() { let vf_type = mk_ty(ctx, false, &[vf_name]); - fields.push(respan(ctx.span, ast::StructField_ { - kind: ast::NamedField(ctx.ext_cx.ident_of("_vftable"), ast::Visibility::Public), + fields.push(ast::StructField { + span: ctx.span, + ident: Some(ctx.ext_cx.ident_of("_vftable")), + vis: ast::Visibility::Public, id: ast::DUMMY_NODE_ID, ty: P(mk_ptrty(ctx, &vf_type, true)), - attrs: Vec::new() - })); + attrs: vec![] + }); } } let mut anon_enum_count = 0; - let mut setters = vec!(); + let mut setters = vec![]; let mut template_args_used = vec![false; template_args.len()]; for m in members.iter() { @@ -987,7 +993,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> if let Some(f) = opt_f { let f_name = match f.bitfields { - Some(ref v) => { + Some(_) => { bitfields += 1; format!("_bitfield_{}", bitfields) } @@ -1011,7 +1017,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> let mut offset: u32 = 0; if let Some(ref bitfields) = f.bitfields { for &(ref bf_name, bf_size) in bitfields.iter() { - setters.push(gen_bitfield_method(ctx, &f_name, bf_name, &f_ty, offset as usize, bf_size)); + 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)) @@ -1037,29 +1043,47 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> // 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 == *arg || match f_ty { - TPtr(ref t, _, _, _) => **t == *arg, - TArray(ref t, _, _) => **t == *arg, - _ => false, - }; + let used = f_ty.signature_contains_type(arg); + if used { template_args_used[index] = true; - needs_full_path = false; + needs_full_path = *arg == f_ty || match f_ty { + TPtr(ref t, _, _, _) => **t != *arg, + TArray(ref t, _, _) => **t != *arg, + _ => true, + }; break; } } - let f_ty = P(cty_to_rs(ctx, &f_ty, f.bitfields.is_none(), needs_full_path)); + 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 { + rust_ty + } + } else { + rust_ty + }; - fields.push(respan(ctx.span, ast::StructField_ { - kind: ast::NamedField( - ctx.ext_cx.ident_of(&f_name), - ast::Visibility::Public, - ), + 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: f_ty, + ty: rust_ty, attrs: mk_doc_attr(ctx, &f.comment) - })); + }); if bypass { continue; } @@ -1090,21 +1114,20 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> let f_name = format!("_phantom{}", phantom_count); phantom_count += 1; let inner_type = P(cty_to_rs(ctx, &arg, true, false)); - fields.push(respan(ctx.span, ast::StructField_ { - kind: ast::NamedField( - ctx.ext_cx.ident_of(&f_name), - ast::Visibility::Public, - ), + 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!(), - })); + attrs: vec![], + }); } if !setters.is_empty() { extra.push(P(ast::Item { ident: ctx.ext_cx.ident_of(""), - attrs: vec!(), + attrs: vec![], id: ast::DUMMY_NODE_ID, node: ast::ItemKind::Impl( ast::Unsafety::Normal, @@ -1125,30 +1148,17 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> } else { ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID) }; - let ty_params = template_args.iter().map(|gt| { - let name = match gt { - &TNamed(ref ti) => { - ctx.ext_cx.ident_of(&ti.borrow().name) - }, - _ => ctx.ext_cx.ident_of("") - }; - ast::TyParam { - ident: name, - id: ast::DUMMY_NODE_ID, - bounds: OwnedSlice::empty(), - default: None, - span: ctx.span - } - }).collect(); + + let ty_params = mk_ty_params(ctx, &template_args); let def = ast::ItemKind::Struct( variant_data, ast::Generics { - lifetimes: vec!(), - ty_params: OwnedSlice::from_vec(ty_params), + lifetimes: vec![], + ty_params: P::from_vec(ty_params), where_clause: ast::WhereClause { id: ast::DUMMY_NODE_ID, - predicates: vec!() + predicates: vec![] } } ); @@ -1177,7 +1187,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> items.push( P(ast::Item { ident: ctx.ext_cx.ident_of(&name), - attrs: vec!(), + attrs: vec![], id: ast::DUMMY_NODE_ID, node: impl_, vis: ast::Visibility::Inherited, @@ -1201,8 +1211,8 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> items.extend(extra.into_iter()); - let mut mangledlist = vec!(); - let mut unmangledlist = vec!(); + let mut mangledlist = vec![]; + let mut unmangledlist = vec![]; let mut unmangle_count: HashMap<String, isize> = HashMap::new(); for v in methodlist { let v = v.clone(); @@ -1224,17 +1234,31 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> _ => unreachable!() } } - if mangledlist.len() > 0 { - items.push(mk_extern(ctx, &vec!(), mangledlist, Abi::C)); + if !mangledlist.is_empty() { + items.push(mk_extern(ctx, &[], mangledlist, Abi::C)); items.push(mk_impl(ctx, id_ty, unmangledlist)); } + + if !ci.vars.is_empty() && template_args.is_empty() { + let vars = ci.vars.into_iter().map(|v| { + let vi = v.varinfo(); + let v = vi.borrow_mut(); + let mut var_name = v.name.clone(); + if !v.mangled.is_empty() { + var_name = format!("{}_consts_{}", name, v.name); + } + cvar_to_rs(ctx, var_name, v.mangled.clone(), &v.ty, v.is_const) + }).collect(); + + items.push(mk_extern(ctx, &[], vars, Abi::C)); + } items } fn opaque_to_rs(ctx: &mut GenCtx, name: &str, _layout: Layout) -> P<ast::Item> { let def = ast::ItemKind::Enum( ast::EnumDef { - variants: vec!() + variants: vec![] }, empty_generics() ); @@ -1277,9 +1301,9 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>> // Nested composites may need to emit declarations and implementations as // they are encountered. The declarations end up in 'extra' and are emitted // after the current union. - let mut extra = vec!(); + let mut extra = vec![]; - fn mk_union_field(ctx: &GenCtx, name: &str, ty: ast::Ty) -> Spanned<ast::StructField_> { + fn mk_union_field(ctx: &GenCtx, name: &str, ty: ast::Ty) -> ast::StructField { let field_ty = if !ctx.options.enable_cxx_namespaces || ctx.current_module_id == ROOT_MODULE_ID { quote_ty!(&ctx.ext_cx, __BindgenUnionField<$ty>) @@ -1287,15 +1311,14 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>> quote_ty!(&ctx.ext_cx, root::__BindgenUnionField<$ty>) }; - respan(ctx.span, ast::StructField_ { - kind: ast::NamedField( - ctx.ext_cx.ident_of(name), - ast::Visibility::Public, - ), + ast::StructField { + span: ctx.span, + ident: Some(ctx.ext_cx.ident_of(name)), + vis: ast::Visibility::Public, id: ast::DUMMY_NODE_ID, ty: field_ty, attrs: vec![], - }) + } } let mut fields = members.iter() @@ -1356,7 +1379,7 @@ fn const_to_rs(ctx: &mut GenCtx, name: String, val: i64, val_ty: ast::Ty) -> P<a let id = first(rust_id(ctx, &name)); P(ast::Item { ident: ctx.ext_cx.ident_of(&id[..]), - attrs: Vec::new(), + attrs: vec![], id: ast::DUMMY_NODE_ID, node: cst, vis: ast::Visibility::Public, @@ -1428,7 +1451,7 @@ fn cenum_to_rs(ctx: &mut GenCtx, // Rust is not happy with univariant enums // if items.len() < 2 { - // return vec!(); + // return vec![]; // } // let mut items = vec![]; @@ -1491,9 +1514,9 @@ fn cenum_to_rs(ctx: &mut GenCtx, })); attrs.push(if ctx.options.derive_debug { - mk_deriving_attr(ctx, &["Debug", "Copy", "Clone"]) + mk_deriving_attr(ctx, &["Debug", "Copy", "Clone", "Eq", "PartialEq", "Hash"]) } else { - mk_deriving_attr(ctx, &["Copy", "Clone"]) + mk_deriving_attr(ctx, &["Copy", "Clone", "Eq", "PartialEq", "Hash"]) }); items.push(P(ast::Item { @@ -1548,7 +1571,7 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize, }; let mut offset = data_offset; - let mut methods = vec!(); + let mut methods = vec![]; for m in members.into_iter() { let advance_by = match *m { CompMember::Field(ref f) => { @@ -1600,13 +1623,13 @@ fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32, is_arg: bool) -> ast::T mk_ty(ctx, false, &[input_type.to_owned()]) } -fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &str, - field_name: &str, field_type: &Type, - offset: usize, width: u32) -> ast::ImplItem { +fn gen_bitfield_methods(ctx: &mut GenCtx, bindgen_name: &str, + field_name: &str, field_type: &Type, + offset: usize, width: u32) -> Vec<ast::ImplItem> { let input_type = type_for_bitfield_width(ctx, width, true); - let width = width % (field_type.layout().unwrap().size as u32 * 8); + let width = width as usize; - let field_type = cty_to_rs(ctx, &field_type, false, true); + let field_type = cty_to_rs(ctx, field_type, false, true); let real_field_name = if field_name.is_empty() { format!("at_offset_{}", offset) @@ -1615,20 +1638,28 @@ fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &str, }; - let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", real_field_name)); let bindgen_ident = ctx.ext_cx.ident_of(bindgen_name); + let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", real_field_name)); + let getter_name = ctx.ext_cx.ident_of(&real_field_name); + let mask = ((1usize << width) - 1) << offset; let item = quote_item!(&ctx.ext_cx, impl X { + #[inline] + pub fn $getter_name(&self) -> $field_type { + (self.$bindgen_ident & ($mask as $field_type)) >> $offset + } + + #[inline] pub fn $setter_name(&mut self, val: $input_type) { - self.$bindgen_ident &= !(((1 << $width as $field_type) - 1) << $offset); - self.$bindgen_ident |= (val as $field_type) << $offset; + self.$bindgen_ident &= !($mask as $field_type); + self.$bindgen_ident |= (val as $field_type << $offset) & ($mask as $field_type); } } ).unwrap(); - match &item.node { - &ast::ItemKind::Impl(_, _, _, _, _, ref items) => items[0].clone(), + match item.node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), _ => unreachable!() } } @@ -1636,7 +1667,7 @@ fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &str, fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, bitfield_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem { let field_type = cty_to_rs(ctx, bitfield_type, false, true); - let mut args = vec!(); + let mut args = vec![]; let mut unnamed: usize = 0; for &(ref name, width) in bitfields.iter() { let ident = if name.is_empty() { @@ -1712,13 +1743,14 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, id: ast::DUMMY_NODE_ID, ident: ctx.ext_cx.ident_of(&format!("new{}", bindgen_name)), vis: ast::Visibility::Public, - attrs: vec!(), + attrs: vec![], node: node, span: ctx.span, + defaultness: ast::Defaultness::Final, } } -fn mk_blob_field(ctx: &GenCtx, name: &str, layout: &Layout) -> Spanned<ast::StructField_> { +fn mk_blob_field(ctx: &GenCtx, name: &str, layout: &Layout) -> ast::StructField { let ty_name = match layout.align { 8 => "u64", 4 => "u32", @@ -1733,15 +1765,14 @@ fn mk_blob_field(ctx: &GenCtx, name: &str, layout: &Layout) -> Spanned<ast::Stru } else { P(mk_arrty(ctx, &base_ty, data_len)) }; - respan(ctx.span, ast::StructField_ { - kind: ast::NamedField( - ctx.ext_cx.ident_of(name), - ast::Visibility::Public, - ), + ast::StructField { + span: ctx.span, + vis: ast::Visibility::Public, + ident: Some(ctx.ext_cx.ident_of(name)), id: ast::DUMMY_NODE_ID, ty: data_ty, - attrs: Vec::new() - }) + attrs: vec![] + } } fn mk_link_name_attr(ctx: &mut GenCtx, name: String) -> ast::Attribute { @@ -1812,7 +1843,7 @@ fn mk_deriving_attr(ctx: &GenCtx, attrs: &[&'static str]) -> ast::Attribute { fn mk_doc_attr(ctx: &GenCtx, doc: &str) -> Vec<ast::Attribute> { if doc.is_empty() { - return vec!(); + return vec![]; } let attr_val = P(respan(ctx.span, ast::MetaItemKind::NameValue( @@ -1833,7 +1864,7 @@ fn cvar_to_rs(ctx: &mut GenCtx, name: String, is_const: bool) -> ast::ForeignItem { let (rust_name, was_mangled) = rust_id(ctx, &name); - let mut attrs = Vec::new(); + let mut attrs = vec![]; if !mangled.is_empty() { attrs.push(mk_link_name_attr(ctx, mangled)); } else if was_mangled { @@ -2051,7 +2082,7 @@ fn cty_is_translatable(ty: &Type) -> bool { } fn mk_ty(ctx: &GenCtx, global: bool, segments: &[String]) -> ast::Ty { - mk_ty_args(ctx, global, segments, vec!()) + mk_ty_args(ctx, global, segments, vec![]) } fn mk_ty_args(ctx: &GenCtx, global: bool, segments: &[String], args: Vec<P<ast::Ty>>) -> ast::Ty { @@ -2065,9 +2096,9 @@ fn mk_ty_args(ctx: &GenCtx, global: bool, segments: &[String], args: Vec<P<ast:: ast::PathSegment { identifier: ctx.ext_cx.ident_of(s), parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: vec!(), - types: OwnedSlice::from_vec(if i == segment_count - 1 { args.clone() } else { vec![] }), - bindings: OwnedSlice::empty(), + lifetimes: vec![], + types: if i == segment_count - 1 { P::from_vec(args.clone()) } else { P::new() }, + bindings: P::new(), }), } }).collect() @@ -2137,7 +2168,7 @@ fn mk_fn_proto_ty(ctx: &mut GenCtx, let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { unsafety: ast::Unsafety::Unsafe, abi: abi, - lifetimes: Vec::new(), + lifetimes: vec![], decl: P(decl.clone()) })); @@ -2152,7 +2183,7 @@ fn mk_fnty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: Abi) -> ast::Ty { let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { unsafety: ast::Unsafety::Unsafe, abi: abi, - lifetimes: Vec::new(), + lifetimes: vec![], decl: P(decl.clone()) })); @@ -2160,31 +2191,31 @@ fn mk_fnty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: Abi) -> ast::Ty { ast::PathSegment { identifier: ctx.ext_cx.ident_of("std"), parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: Vec::new(), - types: OwnedSlice::empty(), - bindings: OwnedSlice::empty(), + lifetimes: vec![], + types: P::new(), + bindings: P::new(), }), }, ast::PathSegment { identifier: ctx.ext_cx.ident_of("option"), parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: Vec::new(), - types: OwnedSlice::empty(), - bindings: OwnedSlice::empty(), + lifetimes: vec![], + types: P::new(), + bindings: P::new(), }), }, ast::PathSegment { identifier: ctx.ext_cx.ident_of("Option"), parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: Vec::new(), - types: OwnedSlice::from_vec(vec!( + lifetimes: vec![], + types: P::from_vec(vec![ P(ast::Ty { id: ast::DUMMY_NODE_ID, node: fnty, span: ctx.span }) - )), - bindings: OwnedSlice::empty(), + ]), + bindings: P::new(), }), } ]; @@ -2230,11 +2261,11 @@ fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> Vec<P<ast::Ite let def = ast::ItemKind::Struct( variant_data, ast::Generics { - lifetimes: vec!(), - ty_params: OwnedSlice::empty(), + lifetimes: vec![], + ty_params: P::new(), where_clause: ast::WhereClause { id: ast::DUMMY_NODE_ID, - predicates: vec!() + predicates: vec![] } } ); @@ -2258,6 +2289,25 @@ fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> Vec<P<ast::Ite ret } +/// Generates a vector of rust's ty params from a list of types +fn mk_ty_params(ctx: &GenCtx, template_args: &[Type]) -> Vec<ast::TyParam> { + template_args.iter().map(|gt| { + let name = match *gt { + TNamed(ref ti) => { + ctx.ext_cx.ident_of(&ti.borrow().name) + }, + _ => ctx.ext_cx.ident_of("") + }; + ast::TyParam { + ident: name, + id: ast::DUMMY_NODE_ID, + bounds: P::new(), + default: None, + span: ctx.span + } + }).collect() +} + fn gen_union_field_definitions_if_necessary(ctx: &mut GenCtx, mut root_mod: &mut ast::Item) { if !ctx.saw_union { return; @@ -2265,6 +2315,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, Debug)] + #[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); ).unwrap(); @@ -1,6 +1,7 @@ #![crate_name = "bindgen"] #![crate_type = "dylib"] #![feature(quote)] +#![feature(borrow_state)] #![cfg_attr(feature = "clippy", feature(plugin))] #![cfg_attr(feature = "clippy", plugin(clippy))] diff --git a/src/parser.rs b/src/parser.rs index be91d769..6b942b2a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -37,6 +37,7 @@ struct ClangParserCtx<'a> { builtin_defs: Vec<Cursor>, module_map: ModuleMap, current_module_id: ModuleId, + current_translation_unit: TranslationUnit, logger: &'a (Logger+'a), err_count: i32, anonymous_modules_found: usize, @@ -71,6 +72,13 @@ fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool { ctx.options.match_pat.iter().any(|pat| name.contains(pat)) } +fn conv_template_type_parameter(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Type { + assert_eq!(cursor.kind(), CXCursor_TemplateTypeParameter); + let ty = conv_ty(ctx, &cursor.cur_type(), cursor); + let layout = Layout::new(ty.size(), ty.align()); + TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout)))) +} + fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { let cursor = cursor.canonical(); let override_enum_ty = ctx.options.override_enum_ty; @@ -101,29 +109,35 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling); let mut has_non_type_template_params = false; - 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 + let args = match ty.num_template_args() { + // In forward declarations, etc, they are in the ast... sigh + -1 => { + let mut args = vec![]; + cursor.visit(|c, _| { + if c.kind() == CXCursor_TemplateTypeParameter { + args.push(conv_template_type_parameter(ctx, c)); + } + CXChildVisit_Continue + }); + args + } + 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 } - _ => vec![], }; let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout); + ci.parser_cursor = Some(cursor); // If it's an instantiation of another template, // find the canonical declaration to find the module @@ -172,8 +186,15 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { } CXCursor_VarDecl => { let mangled = cursor.mangling(); - let vi = Rc::new(RefCell::new(VarInfo::new(spelling, mangled, comment, TVoid))); - GVar(vi) + let is_const = ty.is_const(); + let ty = conv_ty_resolving_typedefs(ctx, &ty, &cursor, true); + let mut vi = VarInfo::new(spelling, mangled, comment, ty); + vi.is_const = is_const; + cursor.visit(|c, _: &Cursor| { + vi.val = visit_literal(c, &ctx.current_translation_unit); + CXChildVisit_Continue + }); + GVar(Rc::new(RefCell::new(vi))) } CXCursor_MacroDefinition => { let vi = Rc::new(RefCell::new(VarInfo::new(spelling, String::new(), comment, TVoid))); @@ -201,13 +222,20 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { } fn opaque_decl(ctx: &mut ClangParserCtx, decl: &Cursor) { + let spelling = decl.spelling(); + let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling); + + if hide { + return; + } + let name = decl_name(ctx, decl); ctx.current_module_mut().globals.push(name); } -fn fwd_decl<F:FnOnce(&mut ClangParserCtx)->()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) { - let def = &cursor.definition(); - if cursor == def { +fn fwd_decl<F: FnOnce(&mut ClangParserCtx)->()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) { + let def = cursor.definition(); + if cursor == &def { f(ctx); } else if def.kind() == CXCursor_NoDeclFound || def.kind() == CXCursor_InvalidFile { @@ -316,12 +344,6 @@ fn mk_fn_sig_resolving_typedefs(ctx: &mut ClangParserCtx, } } -fn conv_decl_ty(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor) -> il::Type { - conv_decl_ty_resolving_typedefs(ctx, ty, cursor, false) -} - fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor, @@ -358,20 +380,25 @@ fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx, let ci = decl.compinfo(); // NB: Args might be filled from decl_name, // it's important not to override - if !args.is_empty() { + // + // We might incur in double borrows here. If that's the case, we're + // already scanning the compinfo, and we'd get the args from the + // ast. + use std::cell::BorrowState; + if !args.is_empty() && ci.borrow_state() == BorrowState::Unused { ci.borrow_mut().args = args; + // XXX: This is a super-dumb way to get the spesialisation, // but it seems to be the only one that'd work here... cursor.visit(|c, _: &Cursor| { if c.kind() == CXCursor_TemplateRef { - let decl = decl_name(ctx, &c.referenced()); + let decl = decl_name(ctx, &c.referenced()); ci.borrow_mut().ref_template = Some(decl.to_type()); } CXChildVisit_Continue }); } - TComp(ci) } CXCursor_EnumDecl => { @@ -451,7 +478,9 @@ fn conv_ty_resolving_typedefs(ctx: &mut ClangParserCtx, CXType_Pointer => conv_ptr_ty_resolving_typedefs(ctx, &ty.pointee_type(), cursor, false, layout, resolve_typedefs), CXType_LValueReference => conv_ptr_ty_resolving_typedefs(ctx, &ty.pointee_type(), cursor, true, layout, resolve_typedefs), // XXX DependentSizedArray is wrong - CXType_VariableArray | CXType_DependentSizedArray | CXType_IncompleteArray => { + CXType_VariableArray | + CXType_DependentSizedArray | + CXType_IncompleteArray => { conv_ptr_ty_resolving_typedefs(ctx, &ty.elem_type(), cursor, false, layout, resolve_typedefs) } CXType_FunctionProto => TFuncProto(mk_fn_sig(ctx, ty, cursor)), @@ -488,6 +517,8 @@ struct Annotations { opaque: bool, hide: bool, use_as: Option<String>, + /// Disable deriving copy/clone on this struct. + no_copy: bool, } impl Annotations { @@ -496,6 +527,7 @@ impl Annotations { opaque: false, hide: false, use_as: None, + no_copy: false, }; anno.parse(&cursor.comment()); @@ -513,6 +545,7 @@ impl Annotations { "opaque" => self.opaque = true, "hide" => self.hide = true, "replaces" => self.use_as = Some(comment.get_tag_attr_value(i)), + "nocopy" => self.no_copy = true, _ => (), } } @@ -530,6 +563,7 @@ impl Annotations { fn visit_composite(cursor: &Cursor, parent: &Cursor, ctx: &mut ClangParserCtx, ci: &mut CompInfo) -> Enum_CXVisitorResult { + assert!(ci.parser_cursor.is_some()); fn is_bitfield_continuation(field: &il::FieldInfo, _ty: &il::Type, width: u32) -> bool { match (&field.bitfields, field.ty.layout()) { (&Some(ref bitfields), Some(layout)) => { @@ -551,9 +585,86 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, } let is_class_typedef = cursor.cur_type().sanitized_spelling_in(&ci.typedefs); + let mutable = cursor.is_mutable_field(); + + let cursor_ty = cursor.cur_type(); // 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 mut ty = conv_ty_resolving_typedefs(ctx, + &cursor_ty, + cursor, + is_class_typedef); + + + use std::cell::BorrowState; + if let Some(child_ci) = ty.get_outermost_composite() { + if let BorrowState::Unused = child_ci.borrow_state() { + let mut child_ci = child_ci.borrow_mut(); + let child_cursor = child_ci.parser_cursor.unwrap(); + + // TODO: This is lame, ideally we should use cursors. + // The problem this loop is trying to solve is + // tests/headers/inner_template_self.hpp, and templates with + // incomplete types. + // + // The problem with this is that, in the first case (see the + // CXCursor_ClassDecl branch below) clang treats the *prev* + // field as a Class Declaration instead of a Class Template, + // so we have to check now for the name and the module id. + // + // Ideally, some method like `semantic_parent` or + // `lexical_parent` should return the reference to the + // class, but I've tried everything I could think about and + // failed miserably. + // + // Also, there could be more complex cases, like a templated + // type in an inner type declaration, that this is + // completely unable to catch. + // + // In the second case (the CXCursor_ClassTemplate branch), + // we're not able to retrieve the template parameters of an + // incomplete type via the declaration or anything like + // that. We can inspect the AST and deduct them though, + // since there's a leading CXCursor_TemplateRef. + if child_ci.args.is_empty() && child_cursor.kind() == CXCursor_ClassDecl { + // println!("child: {:?} {:?}, {:?}, {:?}", cursor.spelling(), + // type_to_str(cursor_ty.kind()), + // type_to_str(child_cursor.cur_type().kind()), + // kind_to_str(child_cursor.kind())); + if child_ci.name == ci.name && + child_ci.module_id == ci.module_id { + child_ci.args = ci.args.clone(); + } + } + + if child_cursor.kind() == CXCursor_ClassTemplate { + // We need to take into account the possibly different + // type template names, so we need to clear them and + // re-scan. + child_ci.args.clear(); + let mut found_invalid_template_ref = false; + cursor.visit(|c, _| { + // println!("ichild: {:?} {:?}, {:?}", c.spelling(), + // kind_to_str(c.kind()), + // type_to_str(c.cur_type().kind())); + if c.kind() == CXCursor_TemplateRef && + c.cur_type().kind() == CXType_Invalid { + found_invalid_template_ref = true; + } + if found_invalid_template_ref && + c.kind() == CXCursor_TypeRef { + child_ci.args.push(TNamed(Rc::new(RefCell::new( + TypeInfo::new(c.spelling(), + ctx.current_module_id, + TVoid, + Layout::zero()))))); + } + CXChildVisit_Continue + }) + } + } + } + let comment = cursor.raw_comment(); let (name, bitfields) = match (cursor.bit_width(), ci.members.last_mut()) { @@ -570,11 +681,12 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, (Some(width), _) => { // Bitfields containing enums are not supported by the c standard // https://stackoverflow.com/questions/11983231/is-it-safe-to-use-an-enum-in-a-bit-field + match ty { - il::TInt(_, _) => (), + il::TInt(..) => {}, _ => { - // NOTE: We rely on the name of the type converted to rust types, - // and on the alignment. + // 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; @@ -599,7 +711,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, ty = TNamed(Rc::new(RefCell::new(ti))) } } - ("".to_owned(), Some(vec!((cursor.spelling(), width)))) + ("".to_owned(), Some(vec![(cursor.spelling(), width)])) }, // The field is not a bitfield (None, _) => (cursor.spelling(), None) @@ -654,13 +766,13 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, }; if should_replace { - *info = FieldInfo::new(name, ty, comment, bitfields); + *info = FieldInfo::new(name, ty, comment, bitfields, mutable); return CXChildVisit_Continue; } } } - let field = FieldInfo::new(name, ty, comment, bitfields); + let field = FieldInfo::new(name, ty, comment, bitfields, mutable); ci.members.push(CompMember::Field(field)); } CXCursor_StructDecl | @@ -679,6 +791,13 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, let new_name = [&*ci.name, &*ci2.borrow().name].join("_").to_owned(); ci2.borrow_mut().name = new_name; + // This clear() is needed because of the speculation we do on + // incomplete types inside visit_composite() members. + // + // If this type ends up being complete, we're going to really + // parse them now, so we should reset them. + ci2.borrow_mut().args.clear(); + // Propagate template arguments and typedefs to inner structs ci2.borrow_mut().args.extend(ci.args.clone().into_iter()); ci2.borrow_mut().typedefs.extend(ci.typedefs.clone().into_iter()); @@ -693,7 +812,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, // Anonymous structs are legal in both C++ and C11 if ci2.borrow().was_unnamed { let ci2b = ci2.borrow(); - let field = FieldInfo::new(ci2b.name.clone(), TComp(ci2.clone()), ci2b.comment.clone(), None); + let field = FieldInfo::new(ci2b.name.clone(), TComp(ci2.clone()), ci2b.comment.clone(), None, false); ci.members.push(CompMember::Field(field)); } }); @@ -702,9 +821,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, ci.layout.packed = true; } CXCursor_TemplateTypeParameter => { - let ty = conv_ty(ctx, &cursor.cur_type(), cursor); - let layout = Layout::new(ty.size(), ty.align()); - ci.args.push(TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout))))); + ci.args.push(conv_template_type_parameter(ctx, cursor)); } CXCursor_EnumDecl => { let anno = Annotations::new(cursor); @@ -751,7 +868,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, ci.typedefs.extend(info.borrow().typedefs.clone().into_iter()); } - let field = FieldInfo::new(fieldname, ty, "".to_owned(), None); + let field = FieldInfo::new(fieldname, ty, "".to_owned(), None, false); if !found_virtual_base && cursor.is_virtual_base() { ci.members.insert(0, CompMember::Field(field)); ci.has_vtable = true; @@ -872,13 +989,26 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, cursor.location()), false); ci.has_non_type_template_params = true; } + CXCursor_VarDecl => { + let linkage = cursor.linkage(); + if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { + return CXChildVisit_Continue; + } + + let visibility = cursor.visibility(); + if visibility != CXVisibility_Default { + return CXChildVisit_Continue; + } + + let var = decl_name(ctx, cursor); + ci.vars.push(var); + } // Intentionally not handled CXCursor_CXXAccessSpecifier | CXCursor_CXXFinalAttr | CXCursor_Constructor | CXCursor_FunctionTemplate | - CXCursor_ConversionFunction | - CXCursor_VarDecl => {} + CXCursor_ConversionFunction => {} _ => { // XXX: Some kind of warning would be nice, but this produces far // too many. @@ -935,8 +1065,7 @@ fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option<i64> { } fn visit_top(cursor: &Cursor, - mut ctx: &mut ClangParserCtx, - unit: &TranslationUnit) -> Enum_CXVisitorResult { + mut ctx: &mut ClangParserCtx) -> Enum_CXVisitorResult { if !match_pattern(ctx, cursor) { return CXChildVisit_Continue; } @@ -953,6 +1082,9 @@ fn visit_top(cursor: &Cursor, fwd_decl(ctx, cursor, move |ctx_| { let decl = decl_name(ctx_, cursor); let ci = decl.compinfo(); + // This clear() is needed because of the speculation we do + // on incomplete types inside visit_composite() members. + ci.borrow_mut().args.clear(); cursor.visit(|c, p| { let mut ci_ = ci.borrow_mut(); visit_composite(c, p, ctx_, &mut ci_) @@ -966,9 +1098,76 @@ fn visit_top(cursor: &Cursor, ci.borrow_mut().hide = true; } + if anno.no_copy { + ci.borrow_mut().no_copy = true; + } + + // If we find a previous translation, we take it now and carry + // on. + // + // XXX: This clone is spurious and could be avoided with another + // scope I think. + let name = ci.borrow().name.clone(); + if let Some(translation) = ctx_.current_module_mut().translations.remove(&name) { + println!("*** {}: found previous translation", name); + if let GComp(ref translated) = translation { + *ci.borrow_mut() = translated.borrow().clone(); + } + } + 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)); + // if the translated type already existed, and we can + // replace it, just do it (tm). + // + // We'll still need the translations map for not found + // translations and stuff like that. + // + // This is a linear search, which is crap, but fwiw it's not + // too common (just when a type marked as translation is + // found). + // + // NB: We have to also loop through the `name` map to take + // declarations in files that haven't been matched into + // account (since they won't appear in globals). + let mut found_in_globals = false; + for v in ctx_.current_module_mut().globals.iter_mut() { + match *v { + GComp(ref mut other_ci) => { + if other_ci.borrow().name == other_type_name { + *other_ci.borrow_mut() = ci.borrow().clone(); + found_in_globals = true; + } + }, + _ => {}, + } + } + + for (cursor, v) in ctx_.name.iter_mut() { + // We can find ourselves here, and that's no fun at + // all. + if *cursor == ci.borrow().parser_cursor.unwrap() { + continue; + } + match *v { + GComp(ref mut other_ci) | + GCompDecl(ref mut other_ci) => { + if other_ci.borrow().name == other_type_name { + // We have to preserve template parameter + // names here if we want to survive. + let args = other_ci.borrow().args.clone(); + *other_ci.borrow_mut() = ci.borrow().clone(); + other_ci.borrow_mut().args = args; + } + } + _ => {} + } + } + + if !found_in_globals { + ctx_.current_module_mut().translations + .insert(other_type_name, GComp(ci)); + } } else { ctx_.current_module_mut().globals.push(GComp(ci)); } @@ -1032,17 +1231,8 @@ fn visit_top(cursor: &Cursor, if visibility != CXVisibility_Default { return CXChildVisit_Continue; } - let ty = conv_ty(ctx, &cursor.cur_type(), cursor); - let var = decl_name(ctx, cursor); - let vi = var.varinfo(); - let mut vi = vi.borrow_mut(); - vi.ty = ty.clone(); - vi.is_const = cursor.cur_type().is_const(); - cursor.visit(|c, _: &Cursor| { - vi.val = visit_literal(c, unit); - CXChildVisit_Continue - }); - ctx.current_module_mut().globals.push(var); + let val = decl_name(ctx, cursor); + ctx.current_module_mut().globals.push(val); CXChildVisit_Continue } @@ -1093,7 +1283,7 @@ fn visit_top(cursor: &Cursor, return CXChildVisit_Recurse; } - let namespace_name = match unit.tokens(cursor) { + let namespace_name = match ctx.current_translation_unit.tokens(cursor) { None => None, Some(tokens) => { if tokens.len() <= 1 { @@ -1130,13 +1320,13 @@ fn visit_top(cursor: &Cursor, let previous_id = ctx.current_module_id; ctx.current_module_id = mod_id; - cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx, &unit)); + cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx)); ctx.current_module_id = previous_id; return CXChildVisit_Continue; } CXCursor_MacroDefinition => { - let val = parse_int_literal_tokens(cursor, unit, 1); + let val = parse_int_literal_tokens(cursor, &ctx.current_translation_unit, 1); if val.is_none() { // Not an integer literal. return CXChildVisit_Continue; @@ -1172,12 +1362,25 @@ fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) { } pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<ModuleMap, ()> { + let ix = cx::Index::create(false, true); + if ix.is_null() { + logger.error("Clang failed to create index"); + return Err(()) + } + + let unit = TranslationUnit::parse(&ix, "", &options.clang_args, &[], CXTranslationUnit_DetailedPreprocessingRecord); + if unit.is_null() { + logger.error("No input files given"); + return Err(()) + } + let mut ctx = ClangParserCtx { options: options, name: HashMap::new(), builtin_defs: vec!(), module_map: ModuleMap::new(), current_module_id: ROOT_MODULE_ID, + current_translation_unit: unit, logger: logger, err_count: 0, anonymous_modules_found: 0, @@ -1185,19 +1388,7 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<ModuleMap, ctx.module_map.insert(ROOT_MODULE_ID, Module::new("root".to_owned(), None)); - let ix = cx::Index::create(false, true); - if ix.is_null() { - ctx.logger.error("Clang failed to create index"); - return Err(()) - } - - let unit = TranslationUnit::parse(&ix, "", &ctx.options.clang_args[..], &[], CXTranslationUnit_DetailedPreprocessingRecord); - if unit.is_null() { - ctx.logger.error("No input files given"); - return Err(()) - } - - let diags = unit.diags(); + let diags = ctx.current_translation_unit.diags(); for d in &diags { let msg = d.format(Diagnostic::default_opts()); let is_err = d.severity() >= CXDiagnostic_Error; @@ -1208,20 +1399,20 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<ModuleMap, return Err(()) } - let cursor = unit.cursor(); + let cursor = ctx.current_translation_unit.cursor(); if ctx.options.emit_ast { cursor.visit(|cur, _: &Cursor| ast_dump(cur, 0)); } - cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx, &unit)); + cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx)); while !ctx.builtin_defs.is_empty() { let c = ctx.builtin_defs.remove(0); - visit_top(&c.definition(), &mut ctx, &unit); + visit_top(&c.definition(), &mut ctx); } - unit.dispose(); + ctx.current_translation_unit.dispose(); ix.dispose(); if ctx.err_count > 0 { diff --git a/src/types.rs b/src/types.rs index cc335d41..4527d710 100644 --- a/src/types.rs +++ b/src/types.rs @@ -10,6 +10,7 @@ pub use self::Global::*; pub use self::Type::*; pub use self::IKind::*; pub use self::FKind::*; +use clang::Cursor; static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT; @@ -54,7 +55,7 @@ impl Module { } } -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum Global { GType(Rc<RefCell<TypeInfo>>), GComp(Rc<RefCell<CompInfo>>), @@ -190,6 +191,15 @@ impl Type { } } + pub fn signature_contains_type(&self, other: &Type) -> bool { + self == other || match *self { + TPtr(ref t, _, _, _) => t.signature_contains_type(other), + TArray(ref t, _, _) => t.signature_contains_type(other), + TComp(ref info) => info.borrow().signature_contains_type(other), + _ => false, + } + } + // XXX Add this info to enums? pub fn was_unnamed(&self) -> bool { match *self { @@ -200,6 +210,15 @@ impl Type { } } + pub fn get_outermost_composite(&self) -> Option<Rc<RefCell<CompInfo>>> { + match *self { + TComp(ref ci) => Some(ci.clone()), + TArray(ref t, _, _) => t.get_outermost_composite(), + TPtr(ref t, _, _, _) => t.get_outermost_composite(), + _ => None, + } + } + pub fn size(&self) -> usize { self.layout().map(|l| l.size).unwrap_or(0) } @@ -281,6 +300,7 @@ impl Type { } } + #[allow(dead_code)] pub fn is_union_like(&self) -> bool { match *self { TArray(ref t, _, _) => t.is_union_like(), @@ -401,6 +421,7 @@ pub struct CompInfo { pub has_destructor: bool, pub has_nonempty_base: bool, pub hide: bool, + pub parser_cursor: Option<Cursor>, /// If this struct should be replaced by an opaque blob. /// /// This is useful if for some reason we can't generate @@ -408,12 +429,16 @@ pub struct CompInfo { pub opaque: bool, pub base_members: usize, pub 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 pub typedefs: Vec<String>, /// If this type has a template parameter which is not a type (e.g.: a size_t) pub has_non_type_template_params: bool, /// If this type was unnamed when parsed pub was_unnamed: bool, + /// Set of static vars declared inside this class. + pub vars: Vec<Global>, /// 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>, @@ -431,7 +456,13 @@ fn unnamed_name(name: String, filename: &String) -> String { } impl CompInfo { - pub fn new(name: String, module_id: ModuleId, filename: String, comment: String, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo { + pub fn new(name: String, + module_id: ModuleId, + filename: String, + comment: String, + kind: CompKind, + members: Vec<CompMember>, + layout: Layout) -> CompInfo { let was_unnamed = name.is_empty(); CompInfo { kind: kind, @@ -440,18 +471,21 @@ impl CompInfo { filename: filename, comment: comment, members: members, - args: vec!(), - methods: vec!(), - vmethods: vec!(), + args: vec![], + methods: vec![], + vmethods: vec![], ref_template: None, has_vtable: false, has_destructor: false, has_nonempty_base: false, hide: false, + parser_cursor: None, opaque: false, + no_copy: false, base_members: 0, layout: layout, - typedefs: vec!(), + typedefs: vec![], + vars: vec![], has_non_type_template_params: false, was_unnamed: was_unnamed, detect_derive_debug_cycle: Cell::new(false), @@ -539,6 +573,9 @@ impl CompInfo { } pub fn can_derive_copy(&self) -> bool { + if self.no_copy { + return false; + } match self.kind { CompKind::Union => true, CompKind::Struct => { @@ -566,6 +603,10 @@ impl CompInfo { } } } + + pub fn signature_contains_type(&self, other: &Type) -> bool { + self.args.iter().any(|t| t.signature_contains_type(other)) + } } impl fmt::Debug for CompInfo { @@ -580,15 +621,22 @@ pub struct FieldInfo { pub ty: Type, pub comment: String, pub bitfields: Option<Vec<(String, u32)>>, + /// If the C++ field is marked as `mutable` + pub mutable: bool, } impl FieldInfo { - pub fn new(name: String, ty: Type, comment: String, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo { + pub fn new(name: String, + ty: Type, + comment: String, + bitfields: Option<Vec<(String, u32)>>, + mutable: bool) -> FieldInfo { FieldInfo { name: name, ty: ty, comment: comment, bitfields: bitfields, + mutable: mutable, } } } diff --git a/tests/expectations/class.rs b/tests/expectations/class.rs index 244e98a4..560c315c 100644 --- a/tests/expectations/class.rs +++ b/tests/expectations/class.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/class_static.rs b/tests/expectations/class_static.rs new file mode 100644 index 00000000..f97875e9 --- /dev/null +++ b/tests/expectations/class_static.rs @@ -0,0 +1,21 @@ +/* automatically generated by rust-bindgen */ + + +#![feature(const_fn)] +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_MyClass; +impl ::std::clone::Clone for Struct_MyClass { + fn clone(&self) -> Self { *self } +} +extern "C" { + #[link_name = "_ZN7MyClass7exampleE"] + pub static mut Struct_MyClass_consts_example: + *const ::std::os::raw::c_int; + #[link_name = "_ZN7MyClass26example_check_no_collisionE"] + pub static mut Struct_MyClass_consts_example_check_no_collision: + *const ::std::os::raw::c_int; +} diff --git a/tests/expectations/class_with_inner_struct.rs b/tests/expectations/class_with_inner_struct.rs index 85954397..d045e911 100644 --- a/tests/expectations/class_with_inner_struct.rs +++ b/tests/expectations/class_with_inner_struct.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] @@ -124,7 +125,7 @@ fn bindgen_test_layout_Struct_B() { assert_eq!(::std::mem::align_of::<Struct_B>() , 4usize); } #[repr(i32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_StepSyntax { Keyword = 0, FunctionalWithoutKeyword = 1, diff --git a/tests/expectations/enum.rs b/tests/expectations/enum.rs index 0b426196..23a599b9 100644 --- a/tests/expectations/enum.rs +++ b/tests/expectations/enum.rs @@ -6,8 +6,8 @@ #[repr(u32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Foo { Bar = 0, Qux = 1, } #[repr(i32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Neg { MinusOne = -1, One = 1, } diff --git a/tests/expectations/enum_and_vtable_mangling.rs b/tests/expectations/enum_and_vtable_mangling.rs index 63e66991..f6b1385a 100644 --- a/tests/expectations/enum_and_vtable_mangling.rs +++ b/tests/expectations/enum_and_vtable_mangling.rs @@ -6,7 +6,7 @@ #[repr(u32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_enum_and_vtable_mangling_hpp_unnamed_1 { match_ = 0, whatever_else = 1, diff --git a/tests/expectations/enum_dupe.rs b/tests/expectations/enum_dupe.rs index 2d691b69..28d7b63d 100644 --- a/tests/expectations/enum_dupe.rs +++ b/tests/expectations/enum_dupe.rs @@ -7,5 +7,5 @@ pub const Dupe: Enum_Foo = Enum_Foo::Bar; #[repr(u32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Foo { Bar = 1, } diff --git a/tests/expectations/enum_explicit_type.rs b/tests/expectations/enum_explicit_type.rs index a5a92d99..cfc1f41d 100644 --- a/tests/expectations/enum_explicit_type.rs +++ b/tests/expectations/enum_explicit_type.rs @@ -6,17 +6,17 @@ #[repr(u8)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Foo { Bar = 0, Qux = 1, } #[repr(i8)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Neg { MinusOne = -1, One = 1, } #[repr(u16)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Bigger { Much = 255, Larger = 256, } #[repr(i64)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_MuchLong { MuchLow = -4294967296, } #[repr(u64)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_MuchLongLong { MuchHigh = 4294967296, } diff --git a/tests/expectations/enum_negative.rs b/tests/expectations/enum_negative.rs index 24b009e9..0a7a36f7 100644 --- a/tests/expectations/enum_negative.rs +++ b/tests/expectations/enum_negative.rs @@ -6,5 +6,5 @@ #[repr(i32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Foo { Bar = -2, Qux = 1, } diff --git a/tests/expectations/enum_packed.rs b/tests/expectations/enum_packed.rs index 12f0bd49..6b3f1b57 100644 --- a/tests/expectations/enum_packed.rs +++ b/tests/expectations/enum_packed.rs @@ -6,11 +6,11 @@ #[repr(u8)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Foo { Bar = 0, Qux = 1, } #[repr(i8)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Neg { MinusOne = -1, One = 1, } #[repr(u16)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Bigger { Much = 255, Larger = 256, } diff --git a/tests/expectations/func_ptr_in_struct.rs b/tests/expectations/func_ptr_in_struct.rs index 970e3122..c177116d 100644 --- a/tests/expectations/func_ptr_in_struct.rs +++ b/tests/expectations/func_ptr_in_struct.rs @@ -6,7 +6,7 @@ #[repr(i32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_baz { _BindgenOpaqueEnum = 0, } #[repr(C)] #[derive(Debug, Copy)] diff --git a/tests/expectations/inner_template_self.rs b/tests/expectations/inner_template_self.rs new file mode 100644 index 00000000..ec8bf6b1 --- /dev/null +++ b/tests/expectations/inner_template_self.rs @@ -0,0 +1,26 @@ +/* automatically generated by rust-bindgen */ + + +#![feature(const_fn)] +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_LinkedList<T> { + pub next: *mut Struct_LinkedList<T>, + pub prev: *mut Struct_LinkedList<T>, +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_InstantiateIt { + pub m_list: Struct_LinkedList<::std::os::raw::c_int>, +} +impl ::std::clone::Clone for Struct_InstantiateIt { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_InstantiateIt() { + assert_eq!(::std::mem::size_of::<Struct_InstantiateIt>() , 16usize); + assert_eq!(::std::mem::align_of::<Struct_InstantiateIt>() , 8usize); +} diff --git a/tests/expectations/jsval_layout_opaque.rs b/tests/expectations/jsval_layout_opaque.rs index 33c2ce32..760ac1f2 100644 --- a/tests/expectations/jsval_layout_opaque.rs +++ b/tests/expectations/jsval_layout_opaque.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] @@ -25,7 +26,7 @@ impl <T> ::std::clone::Clone for __BindgenUnionField<T> { } pub const JSVAL_TAG_SHIFT: ::std::os::raw::c_uint = 47; #[repr(u8)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum JSValueType { JSVAL_TYPE_DOUBLE = 0, JSVAL_TYPE_INT32 = 1, @@ -40,7 +41,7 @@ pub enum JSValueType { JSVAL_TYPE_MISSING = 33, } #[repr(u32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum JSValueTag { JSVAL_TAG_MAX_DOUBLE = 131056, JSVAL_TAG_INT32 = 131057, @@ -53,7 +54,7 @@ pub enum JSValueTag { JSVAL_TAG_OBJECT = 131064, } #[repr(u64)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum JSValueShiftedTag { JSVAL_SHIFTED_TAG_MAX_DOUBLE = 18444492278190833663, JSVAL_SHIFTED_TAG_INT32 = 18444633011384221696, @@ -66,7 +67,7 @@ pub enum JSValueShiftedTag { JSVAL_SHIFTED_TAG_OBJECT = 18445618173802708992, } #[repr(u32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum JSWhyMagic { JS_ELEMENTS_HOLE = 0, JS_NO_ITER_VALUE = 1, @@ -146,13 +147,25 @@ pub struct jsval_layout_jsval_layout_opaque_hpp_unnamed_1 { pub _bitfield_1: u64, } impl jsval_layout_jsval_layout_opaque_hpp_unnamed_1 { + #[inline] + pub fn payload47(&self) -> u64 { + (self._bitfield_1 & (140737488355327usize as u64)) >> 0usize + } + #[inline] pub fn set_payload47(&mut self, val: u32) { - self._bitfield_1 &= !(((1 << (47u32 as u64)) - 1) << 0usize); - self._bitfield_1 |= (val as u64) << 0usize; + self._bitfield_1 &= !(140737488355327usize as u64); + self._bitfield_1 |= + ((val as u64) << 0usize) & (140737488355327usize as u64); } + #[inline] + pub fn tag(&self) -> u64 { + (self._bitfield_1 & (18446603336221196288usize as u64)) >> 47usize + } + #[inline] pub fn set_tag(&mut self, val: u32) { - self._bitfield_1 &= !(((1 << (17u32 as u64)) - 1) << 47usize); - self._bitfield_1 |= (val as u64) << 47usize; + self._bitfield_1 &= !(18446603336221196288usize as u64); + self._bitfield_1 |= + ((val as u64) << 47usize) & (18446603336221196288usize as u64); } pub const fn new_bitfield_1(payload47: u32, tag: u32) -> u64 { 0 | ((payload47 as u64) << 0u32) | ((tag as u64) << 47u32) diff --git a/tests/expectations/mutable.rs b/tests/expectations/mutable.rs new file mode 100644 index 00000000..62b4c524 --- /dev/null +++ b/tests/expectations/mutable.rs @@ -0,0 +1,43 @@ +/* automatically generated by rust-bindgen */ + + +#![feature(const_fn)] +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_C { + pub m_member: ::std::os::raw::c_int, + pub m_other: ::std::os::raw::c_int, +} +impl ::std::clone::Clone for Struct_C { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_C() { + assert_eq!(::std::mem::size_of::<Struct_C>() , 8usize); + assert_eq!(::std::mem::align_of::<Struct_C>() , 4usize); +} +#[repr(C)] +#[derive(Debug)] +pub struct Struct_NonCopiable { + pub m_member: ::std::cell::Cell<::std::os::raw::c_int>, +} +#[test] +fn bindgen_test_layout_Struct_NonCopiable() { + assert_eq!(::std::mem::size_of::<Struct_NonCopiable>() , 4usize); + assert_eq!(::std::mem::align_of::<Struct_NonCopiable>() , 4usize); +} +#[repr(C)] +#[derive(Debug)] +pub struct Struct_NonCopiableWithNonCopiableMutableMember { + pub m_member: ::std::cell::UnsafeCell<Struct_NonCopiable>, +} +#[test] +fn bindgen_test_layout_Struct_NonCopiableWithNonCopiableMutableMember() { + assert_eq!(::std::mem::size_of::<Struct_NonCopiableWithNonCopiableMutableMember>() + , 4usize); + assert_eq!(::std::mem::align_of::<Struct_NonCopiableWithNonCopiableMutableMember>() + , 4usize); +} diff --git a/tests/expectations/namespace.rs b/tests/expectations/namespace.rs index 59c6c349..4d9225f3 100644 --- a/tests/expectations/namespace.rs +++ b/tests/expectations/namespace.rs @@ -14,6 +14,7 @@ pub mod root { pub m_c: T, pub m_c_ptr: *mut T, pub m_c_arr: [T; 10usize], + pub _phantom0: ::std::marker::PhantomData<T>, } extern "C" { #[link_name = "_Z9top_levelv"] @@ -57,7 +58,6 @@ pub mod root { #[derive(Debug)] pub struct Struct_D<T> { pub m_c: root::Struct_C<T>, - pub _phantom0: ::std::marker::PhantomData<T>, } extern "C" { #[link_name = "_ZN1w3hehEv"] diff --git a/tests/expectations/no_copy.rs b/tests/expectations/no_copy.rs new file mode 100644 index 00000000..95a733b6 --- /dev/null +++ b/tests/expectations/no_copy.rs @@ -0,0 +1,14 @@ +/* automatically generated by rust-bindgen */ + + +#![feature(const_fn)] +#![allow(non_snake_case)] + + +/** <div rustbindgen nocopy></div> */ +#[repr(C)] +#[derive(Debug)] +pub struct Struct_CopiableButWait<T> { + pub whatever: ::std::os::raw::c_int, + pub _phantom0: ::std::marker::PhantomData<T>, +} diff --git a/tests/expectations/nsStyleAutoArray.rs b/tests/expectations/nsStyleAutoArray.rs new file mode 100644 index 00000000..28207639 --- /dev/null +++ b/tests/expectations/nsStyleAutoArray.rs @@ -0,0 +1,23 @@ +/* automatically generated by rust-bindgen */ + + +#![feature(const_fn)] +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_nsTArray<T> { + pub mBuff: *mut T, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_nsStyleAutoArray<T> { + pub mFirstElement: T, + pub mOtherElements: Struct_nsTArray<T>, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum nsStyleAutoArray_WithSingleInitialElement { + WITH_SINGLE_INITIAL_ELEMENT = 0, +} diff --git a/tests/expectations/only_bitfields.rs b/tests/expectations/only_bitfields.rs index 86ed8564..88345373 100644 --- a/tests/expectations/only_bitfields.rs +++ b/tests/expectations/only_bitfields.rs @@ -11,13 +11,19 @@ pub struct Struct_C { pub _bitfield_1: u8, } impl Struct_C { + #[inline] + pub fn a(&self) -> u8 { (self._bitfield_1 & (1usize as u8)) >> 0usize } + #[inline] pub fn set_a(&mut self, val: bool) { - self._bitfield_1 &= !(((1 << (1u32 as u8)) - 1) << 0usize); - self._bitfield_1 |= (val as u8) << 0usize; + self._bitfield_1 &= !(1usize as u8); + self._bitfield_1 |= ((val as u8) << 0usize) & (1usize as u8); } + #[inline] + pub fn b(&self) -> u8 { (self._bitfield_1 & (254usize as u8)) >> 1usize } + #[inline] pub fn set_b(&mut self, val: u8) { - self._bitfield_1 &= !(((1 << (7u32 as u8)) - 1) << 1usize); - self._bitfield_1 |= (val as u8) << 1usize; + self._bitfield_1 &= !(254usize as u8); + self._bitfield_1 |= ((val as u8) << 1usize) & (254usize as u8); } pub const fn new_bitfield_1(a: bool, b: u8) -> u8 { 0 | ((a as u8) << 0u32) | ((b as u8) << 1u32) diff --git a/tests/expectations/opaque_typedef.rs b/tests/expectations/opaque_typedef.rs new file mode 100644 index 00000000..7dfa0ff9 --- /dev/null +++ b/tests/expectations/opaque_typedef.rs @@ -0,0 +1,17 @@ +/* automatically generated by rust-bindgen */ + + +#![feature(const_fn)] +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_RandomTemplate<T> { + pub _phantom0: ::std::marker::PhantomData<T>, +} +pub enum Struct_Wat { } +pub enum Struct_Wat3 { } +#[repr(C)] +pub struct ShouldBeOpaque; +pub type ShouldNotBeOpaque = Struct_RandomTemplate<::std::os::raw::c_int>; diff --git a/tests/expectations/overflowed_enum.rs b/tests/expectations/overflowed_enum.rs index e32db0ae..7b6de96b 100644 --- a/tests/expectations/overflowed_enum.rs +++ b/tests/expectations/overflowed_enum.rs @@ -6,12 +6,12 @@ #[repr(u32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Foo { BAP_ARM = 9698489, BAP_X86 = 11960045, BAP_X86_64 = 3128633167, } #[repr(u16)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_Bar { One = 1, Big = 2, } diff --git a/tests/expectations/struct_with_anon_union.rs b/tests/expectations/struct_with_anon_union.rs index ce5d6357..668b1273 100644 --- a/tests/expectations/struct_with_anon_union.rs +++ b/tests/expectations/struct_with_anon_union.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/struct_with_anon_unnamed_union.rs b/tests/expectations/struct_with_anon_unnamed_union.rs index d5871b1a..5df5f61b 100644 --- a/tests/expectations/struct_with_anon_unnamed_union.rs +++ b/tests/expectations/struct_with_anon_unnamed_union.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/struct_with_bitfields.rs b/tests/expectations/struct_with_bitfields.rs index ab2acf2a..26003ebd 100644 --- a/tests/expectations/struct_with_bitfields.rs +++ b/tests/expectations/struct_with_bitfields.rs @@ -14,35 +14,71 @@ pub struct Struct_bitfield { pub _bitfield_3: ::std::os::raw::c_uint, } impl Struct_bitfield { + #[inline] + pub fn a(&self) -> ::std::os::raw::c_ushort { + (self._bitfield_1 & (1usize as ::std::os::raw::c_ushort)) >> 0usize + } + #[inline] pub fn set_a(&mut self, val: bool) { - self._bitfield_1 &= - !(((1 << (1u32 as ::std::os::raw::c_ushort)) - 1) << 0usize); - self._bitfield_1 |= (val as ::std::os::raw::c_ushort) << 0usize; + self._bitfield_1 &= !(1usize as ::std::os::raw::c_ushort); + self._bitfield_1 |= + ((val as ::std::os::raw::c_ushort) << 0usize) & + (1usize as ::std::os::raw::c_ushort); + } + #[inline] + pub fn b(&self) -> ::std::os::raw::c_ushort { + (self._bitfield_1 & (2usize as ::std::os::raw::c_ushort)) >> 1usize } + #[inline] pub fn set_b(&mut self, val: bool) { - self._bitfield_1 &= - !(((1 << (1u32 as ::std::os::raw::c_ushort)) - 1) << 1usize); - self._bitfield_1 |= (val as ::std::os::raw::c_ushort) << 1usize; + self._bitfield_1 &= !(2usize as ::std::os::raw::c_ushort); + self._bitfield_1 |= + ((val as ::std::os::raw::c_ushort) << 1usize) & + (2usize as ::std::os::raw::c_ushort); } + #[inline] + pub fn c(&self) -> ::std::os::raw::c_ushort { + (self._bitfield_1 & (4usize as ::std::os::raw::c_ushort)) >> 2usize + } + #[inline] pub fn set_c(&mut self, val: bool) { - self._bitfield_1 &= - !(((1 << (1u32 as ::std::os::raw::c_ushort)) - 1) << 2usize); - self._bitfield_1 |= (val as ::std::os::raw::c_ushort) << 2usize; + self._bitfield_1 &= !(4usize as ::std::os::raw::c_ushort); + self._bitfield_1 |= + ((val as ::std::os::raw::c_ushort) << 2usize) & + (4usize as ::std::os::raw::c_ushort); + } + #[inline] + pub fn at_offset_3(&self) -> ::std::os::raw::c_ushort { + (self._bitfield_1 & (8usize as ::std::os::raw::c_ushort)) >> 3usize } + #[inline] pub fn set_at_offset_3(&mut self, val: bool) { - self._bitfield_1 &= - !(((1 << (1u32 as ::std::os::raw::c_ushort)) - 1) << 3usize); - self._bitfield_1 |= (val as ::std::os::raw::c_ushort) << 3usize; + self._bitfield_1 &= !(8usize as ::std::os::raw::c_ushort); + self._bitfield_1 |= + ((val as ::std::os::raw::c_ushort) << 3usize) & + (8usize as ::std::os::raw::c_ushort); } + #[inline] + pub fn at_offset_4(&self) -> ::std::os::raw::c_ushort { + (self._bitfield_1 & (48usize as ::std::os::raw::c_ushort)) >> 4usize + } + #[inline] pub fn set_at_offset_4(&mut self, val: u8) { - self._bitfield_1 &= - !(((1 << (2u32 as ::std::os::raw::c_ushort)) - 1) << 4usize); - self._bitfield_1 |= (val as ::std::os::raw::c_ushort) << 4usize; + self._bitfield_1 &= !(48usize as ::std::os::raw::c_ushort); + self._bitfield_1 |= + ((val as ::std::os::raw::c_ushort) << 4usize) & + (48usize as ::std::os::raw::c_ushort); + } + #[inline] + pub fn d(&self) -> ::std::os::raw::c_ushort { + (self._bitfield_1 & (192usize as ::std::os::raw::c_ushort)) >> 6usize } + #[inline] pub fn set_d(&mut self, val: u8) { - self._bitfield_1 &= - !(((1 << (2u32 as ::std::os::raw::c_ushort)) - 1) << 6usize); - self._bitfield_1 |= (val as ::std::os::raw::c_ushort) << 6usize; + self._bitfield_1 &= !(192usize as ::std::os::raw::c_ushort); + self._bitfield_1 |= + ((val as ::std::os::raw::c_ushort) << 6usize) & + (192usize as ::std::os::raw::c_ushort); } pub const fn new_bitfield_1(a: bool, b: bool, c: bool, unnamed_bitfield1: bool, @@ -55,18 +91,31 @@ impl Struct_bitfield { ((unnamed_bitfield2 as ::std::os::raw::c_ushort) << 4u32) | ((d as ::std::os::raw::c_ushort) << 6u32) } + #[inline] + pub fn f(&self) -> ::std::os::raw::c_uint { + (self._bitfield_2 & (3usize as ::std::os::raw::c_uint)) >> 0usize + } + #[inline] pub fn set_f(&mut self, val: u8) { - self._bitfield_2 &= - !(((1 << (2u32 as ::std::os::raw::c_uint)) - 1) << 0usize); - self._bitfield_2 |= (val as ::std::os::raw::c_uint) << 0usize; + self._bitfield_2 &= !(3usize as ::std::os::raw::c_uint); + self._bitfield_2 |= + ((val as ::std::os::raw::c_uint) << 0usize) & + (3usize as ::std::os::raw::c_uint); } pub const fn new_bitfield_2(f: u8) -> ::std::os::raw::c_uint { 0 | ((f as ::std::os::raw::c_uint) << 0u32) } + #[inline] + pub fn g(&self) -> ::std::os::raw::c_uint { + (self._bitfield_3 & (4294967295usize as ::std::os::raw::c_uint)) >> + 0usize + } + #[inline] pub fn set_g(&mut self, val: u32) { - self._bitfield_3 &= - !(((1 << (0u32 as ::std::os::raw::c_uint)) - 1) << 0usize); - self._bitfield_3 |= (val as ::std::os::raw::c_uint) << 0usize; + self._bitfield_3 &= !(4294967295usize as ::std::os::raw::c_uint); + self._bitfield_3 |= + ((val as ::std::os::raw::c_uint) << 0usize) & + (4294967295usize as ::std::os::raw::c_uint); } pub const fn new_bitfield_3(g: u32) -> ::std::os::raw::c_uint { 0 | ((g as ::std::os::raw::c_uint) << 0u32) diff --git a/tests/expectations/struct_with_nesting.rs b/tests/expectations/struct_with_nesting.rs index 2e023c33..787a174d 100644 --- a/tests/expectations/struct_with_nesting.rs +++ b/tests/expectations/struct_with_nesting.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/template.rs b/tests/expectations/template.rs index 63f2d952..02e683a8 100644 --- a/tests/expectations/template.rs +++ b/tests/expectations/template.rs @@ -74,6 +74,81 @@ fn bindgen_test_layout_Struct_POD() { assert_eq!(::std::mem::size_of::<Struct_POD>() , 4usize); assert_eq!(::std::mem::align_of::<Struct_POD>() , 4usize); } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_NestedBase<T, U> { + pub buff: *mut T, + pub _phantom0: ::std::marker::PhantomData<U>, +} +/** + * <div rustbindgen replaces="NestedReplaced"></div> + */ +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_NestedReplaced<T> { + pub buff: *mut T, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_NestedContainer<T> { + pub c: T, + pub nested: Struct_NestedReplaced<T>, + pub inc: Struct_Incomplete<T>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_Incomplete<T> { + pub d: T, +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_Untemplated; +impl ::std::clone::Clone for Struct_Untemplated { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_Templated<T> { + pub m_untemplated: Struct_Untemplated, + pub _phantom0: ::std::marker::PhantomData<T>, +} +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + * <div rustbindgen replaces="ReplacedWithoutDestructor"></div> + */ +#[repr(C)] +#[derive(Debug)] +pub struct Struct_ReplacedWithoutDestructor<T> { + pub buff: *mut T, +} +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + * <div rustbindgen replaces="ReplacedWithoutDestructorFwd"></div> + */ +#[repr(C)] +#[derive(Debug)] +pub struct Struct_ReplacedWithoutDestructorFwd<T> { + pub buff: *mut T, +} +#[repr(C)] +#[derive(Debug)] +pub struct Struct_ShouldNotBeCopiable<T> { + pub m_member: Struct_ReplacedWithoutDestructor<T>, +} +#[repr(C)] +#[derive(Debug)] +pub struct Struct_ShouldNotBeCopiableAsWell<U> { + pub m_member: Struct_ReplacedWithoutDestructorFwd<U>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Struct_TemplateWithVar<T> { + pub _phantom0: ::std::marker::PhantomData<T>, +} extern "C" { #[link_name = "_Z3bar3FooIiiE"] pub fn bar(foo: Struct_Foo<::std::os::raw::c_int, ::std::os::raw::c_int>); diff --git a/tests/expectations/union_fields.rs b/tests/expectations/union_fields.rs index cf750844..974a8f71 100644 --- a/tests/expectations/union_fields.rs +++ b/tests/expectations/union_fields.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/union_with_anon_struct.rs b/tests/expectations/union_with_anon_struct.rs index 076e263f..3f78fb85 100644 --- a/tests/expectations/union_with_anon_struct.rs +++ b/tests/expectations/union_with_anon_struct.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/union_with_anon_struct_bitfield.rs b/tests/expectations/union_with_anon_struct_bitfield.rs index dc96c5c8..26b428f5 100644 --- a/tests/expectations/union_with_anon_struct_bitfield.rs +++ b/tests/expectations/union_with_anon_struct_bitfield.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] @@ -55,15 +56,28 @@ pub struct Struct_foo_union_with_anon_struct_bitfield_h_unnamed_1 { pub _bitfield_1: ::std::os::raw::c_int, } impl Struct_foo_union_with_anon_struct_bitfield_h_unnamed_1 { + #[inline] + pub fn b(&self) -> ::std::os::raw::c_int { + (self._bitfield_1 & (127usize as ::std::os::raw::c_int)) >> 0usize + } + #[inline] pub fn set_b(&mut self, val: u8) { - self._bitfield_1 &= - !(((1 << (7u32 as ::std::os::raw::c_int)) - 1) << 0usize); - self._bitfield_1 |= (val as ::std::os::raw::c_int) << 0usize; + self._bitfield_1 &= !(127usize as ::std::os::raw::c_int); + self._bitfield_1 |= + ((val as ::std::os::raw::c_int) << 0usize) & + (127usize as ::std::os::raw::c_int); } + #[inline] + pub fn c(&self) -> ::std::os::raw::c_int { + (self._bitfield_1 & (4294967168usize as ::std::os::raw::c_int)) >> + 7usize + } + #[inline] pub fn set_c(&mut self, val: u32) { - self._bitfield_1 &= - !(((1 << (25u32 as ::std::os::raw::c_int)) - 1) << 7usize); - self._bitfield_1 |= (val as ::std::os::raw::c_int) << 7usize; + self._bitfield_1 &= !(4294967168usize as ::std::os::raw::c_int); + self._bitfield_1 |= + ((val as ::std::os::raw::c_int) << 7usize) & + (4294967168usize as ::std::os::raw::c_int); } pub const fn new_bitfield_1(b: u8, c: u32) -> ::std::os::raw::c_int { 0 | ((b as ::std::os::raw::c_int) << 0u32) | diff --git a/tests/expectations/union_with_anon_union.rs b/tests/expectations/union_with_anon_union.rs index fc354db4..9ea9b841 100644 --- a/tests/expectations/union_with_anon_union.rs +++ b/tests/expectations/union_with_anon_union.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/union_with_anon_unnamed_struct.rs b/tests/expectations/union_with_anon_unnamed_struct.rs index d75c120f..80e28512 100644 --- a/tests/expectations/union_with_anon_unnamed_struct.rs +++ b/tests/expectations/union_with_anon_unnamed_struct.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/union_with_anon_unnamed_union.rs b/tests/expectations/union_with_anon_unnamed_union.rs index 4f26bfc9..a502f1f3 100644 --- a/tests/expectations/union_with_anon_unnamed_union.rs +++ b/tests/expectations/union_with_anon_unnamed_union.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/union_with_big_member.rs b/tests/expectations/union_with_big_member.rs index 44fc317b..122d5a64 100644 --- a/tests/expectations/union_with_big_member.rs +++ b/tests/expectations/union_with_big_member.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/union_with_nesting.rs b/tests/expectations/union_with_nesting.rs index 0a884d4a..070cc045 100644 --- a/tests/expectations/union_with_nesting.rs +++ b/tests/expectations/union_with_nesting.rs @@ -6,6 +6,7 @@ #[derive(Copy, Debug)] +#[repr(C)] pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); impl <T> __BindgenUnionField<T> { #[inline] diff --git a/tests/expectations/weird_bitfields.rs b/tests/expectations/weird_bitfields.rs index 405c2490..d2ae1f96 100644 --- a/tests/expectations/weird_bitfields.rs +++ b/tests/expectations/weird_bitfields.rs @@ -6,7 +6,7 @@ #[repr(u32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Enum_nsStyleSVGOpacitySource { eStyleSVGOpacitySource_Normal = 0, eStyleSVGOpacitySource_ContextFillOpacity = 1, @@ -31,40 +31,78 @@ pub struct Struct_Weird { pub _bitfield_2: u32, } impl Struct_Weird { + #[inline] + pub fn bitTest(&self) -> ::std::os::raw::c_uint { + (self._bitfield_1 & (65535usize as ::std::os::raw::c_uint)) >> 0usize + } + #[inline] pub fn set_bitTest(&mut self, val: u16) { - self._bitfield_1 &= - !(((1 << (16u32 as ::std::os::raw::c_uint)) - 1) << 0usize); - self._bitfield_1 |= (val as ::std::os::raw::c_uint) << 0usize; + self._bitfield_1 &= !(65535usize as ::std::os::raw::c_uint); + self._bitfield_1 |= + ((val as ::std::os::raw::c_uint) << 0usize) & + (65535usize as ::std::os::raw::c_uint); + } + #[inline] + pub fn bitTest2(&self) -> ::std::os::raw::c_uint { + (self._bitfield_1 & (2147418112usize as ::std::os::raw::c_uint)) >> + 16usize } + #[inline] pub fn set_bitTest2(&mut self, val: u16) { - self._bitfield_1 &= - !(((1 << (15u32 as ::std::os::raw::c_uint)) - 1) << 16usize); - self._bitfield_1 |= (val as ::std::os::raw::c_uint) << 16usize; + self._bitfield_1 &= !(2147418112usize as ::std::os::raw::c_uint); + self._bitfield_1 |= + ((val as ::std::os::raw::c_uint) << 16usize) & + (2147418112usize as ::std::os::raw::c_uint); } pub const fn new_bitfield_1(bitTest: u16, bitTest2: u16) -> ::std::os::raw::c_uint { 0 | ((bitTest as ::std::os::raw::c_uint) << 0u32) | ((bitTest2 as ::std::os::raw::c_uint) << 16u32) } + #[inline] + pub fn mFillOpacitySource(&self) -> u32 { + (self._bitfield_2 & (7usize as u32)) >> 0usize + } + #[inline] pub fn set_mFillOpacitySource(&mut self, val: u8) { - self._bitfield_2 &= !(((1 << (3u32 as u32)) - 1) << 0usize); - self._bitfield_2 |= (val as u32) << 0usize; + self._bitfield_2 &= !(7usize as u32); + self._bitfield_2 |= ((val as u32) << 0usize) & (7usize as u32); + } + #[inline] + pub fn mStrokeOpacitySource(&self) -> u32 { + (self._bitfield_2 & (56usize as u32)) >> 3usize } + #[inline] pub fn set_mStrokeOpacitySource(&mut self, val: u8) { - self._bitfield_2 &= !(((1 << (3u32 as u32)) - 1) << 3usize); - self._bitfield_2 |= (val as u32) << 3usize; + self._bitfield_2 &= !(56usize as u32); + self._bitfield_2 |= ((val as u32) << 3usize) & (56usize as u32); } + #[inline] + pub fn mStrokeDasharrayFromObject(&self) -> u32 { + (self._bitfield_2 & (64usize as u32)) >> 6usize + } + #[inline] pub fn set_mStrokeDasharrayFromObject(&mut self, val: bool) { - self._bitfield_2 &= !(((1 << (1u32 as u32)) - 1) << 6usize); - self._bitfield_2 |= (val as u32) << 6usize; + self._bitfield_2 &= !(64usize as u32); + self._bitfield_2 |= ((val as u32) << 6usize) & (64usize as u32); + } + #[inline] + pub fn mStrokeDashoffsetFromObject(&self) -> u32 { + (self._bitfield_2 & (128usize as u32)) >> 7usize } + #[inline] pub fn set_mStrokeDashoffsetFromObject(&mut self, val: bool) { - self._bitfield_2 &= !(((1 << (1u32 as u32)) - 1) << 7usize); - self._bitfield_2 |= (val as u32) << 7usize; + self._bitfield_2 &= !(128usize as u32); + self._bitfield_2 |= ((val as u32) << 7usize) & (128usize as u32); + } + #[inline] + pub fn mStrokeWidthFromObject(&self) -> u32 { + (self._bitfield_2 & (256usize as u32)) >> 8usize } + #[inline] pub fn set_mStrokeWidthFromObject(&mut self, val: bool) { - self._bitfield_2 &= !(((1 << (1u32 as u32)) - 1) << 8usize); - self._bitfield_2 |= (val as u32) << 8usize; + self._bitfield_2 &= !(256usize as u32); + self._bitfield_2 |= ((val as u32) << 8usize) & (256usize as u32); } pub const fn new_bitfield_2(mFillOpacitySource: u8, mStrokeOpacitySource: u8, diff --git a/tests/headers/class_static.hpp b/tests/headers/class_static.hpp new file mode 100644 index 00000000..21ab2321 --- /dev/null +++ b/tests/headers/class_static.hpp @@ -0,0 +1,7 @@ +class MyClass { +public: + static const int* example; + static const int* example_check_no_collision; +}; + +static const int* example_check_no_collision; diff --git a/tests/headers/inner_template_self.hpp b/tests/headers/inner_template_self.hpp new file mode 100644 index 00000000..1ae5af06 --- /dev/null +++ b/tests/headers/inner_template_self.hpp @@ -0,0 +1,10 @@ + +template <typename T> +class LinkedList { + LinkedList<T>* next; + LinkedList* prev; +}; + +class InstantiateIt { + LinkedList<int> m_list; +}; diff --git a/tests/headers/mutable.hpp b/tests/headers/mutable.hpp new file mode 100644 index 00000000..b61a1031 --- /dev/null +++ b/tests/headers/mutable.hpp @@ -0,0 +1,14 @@ +class C { + mutable int m_member; + int m_other; +}; + +class NonCopiable { + mutable int m_member; + + ~NonCopiable() {}; +}; + +class NonCopiableWithNonCopiableMutableMember { + mutable NonCopiable m_member; +}; diff --git a/tests/headers/no_copy.hpp b/tests/headers/no_copy.hpp new file mode 100644 index 00000000..349e428e --- /dev/null +++ b/tests/headers/no_copy.hpp @@ -0,0 +1,6 @@ + +/** <div rustbindgen nocopy></div> */ +template<typename T> +class CopiableButWait { + int whatever; +}; diff --git a/tests/headers/nsStyleAutoArray.hpp b/tests/headers/nsStyleAutoArray.hpp new file mode 100644 index 00000000..950152c0 --- /dev/null +++ b/tests/headers/nsStyleAutoArray.hpp @@ -0,0 +1,57 @@ + +template<typename T> +class nsTArray { + T* mBuff; +}; + +template<typename T> +class nsStyleAutoArray +{ +public: + // This constructor places a single element in mFirstElement. + enum WithSingleInitialElement { WITH_SINGLE_INITIAL_ELEMENT }; + explicit nsStyleAutoArray(WithSingleInitialElement) {} + nsStyleAutoArray(const nsStyleAutoArray& aOther) { *this = aOther; } + nsStyleAutoArray& operator=(const nsStyleAutoArray& aOther) { + mFirstElement = aOther.mFirstElement; + mOtherElements = aOther.mOtherElements; + return *this; + } + + bool operator==(const nsStyleAutoArray& aOther) const { + return Length() == aOther.Length() && + mFirstElement == aOther.mFirstElement && + mOtherElements == aOther.mOtherElements; + } + bool operator!=(const nsStyleAutoArray& aOther) const { + return !(*this == aOther); + } + + unsigned long Length() const { + return mOtherElements.Length() + 1; + } + const T& operator[](unsigned long aIndex) const { + return aIndex == 0 ? mFirstElement : mOtherElements[aIndex - 1]; + } + T& operator[](unsigned long aIndex) { + return aIndex == 0 ? mFirstElement : mOtherElements[aIndex - 1]; + } + + void EnsureLengthAtLeast(unsigned long aMinLen) { + if (aMinLen > 0) { + mOtherElements.EnsureLengthAtLeast(aMinLen - 1); + } + } + + void SetLengthNonZero(unsigned long aNewLen) { + mOtherElements.SetLength(aNewLen - 1); + } + + void TruncateLengthNonZero(unsigned long aNewLen) { + mOtherElements.TruncateLength(aNewLen - 1); + } + +private: + T mFirstElement; + nsTArray<T> mOtherElements; +}; diff --git a/tests/headers/opaque_typedef.hpp b/tests/headers/opaque_typedef.hpp new file mode 100644 index 00000000..23bb363a --- /dev/null +++ b/tests/headers/opaque_typedef.hpp @@ -0,0 +1,17 @@ +// bindgen-flags: -std=c++11 +template<typename T> +class RandomTemplate; + +template<int i> +class Wat; + +template<int i> +class Wat3; + +template<> +class Wat3<3>; + +/** <div rustbindgen opaque></div> */ +typedef RandomTemplate<int> ShouldBeOpaque; + +typedef RandomTemplate<int> ShouldNotBeOpaque; diff --git a/tests/headers/template.hpp b/tests/headers/template.hpp index e53ecbc8..c13643c3 100644 --- a/tests/headers/template.hpp +++ b/tests/headers/template.hpp @@ -55,3 +55,90 @@ class Opaque { class POD { Opaque<int> opaque_member; }; + +/** + * <div rustbindgen replaces="NestedReplaced"></div> + */ +template<typename T> +class Nested { + T* buff; +}; + +template<typename T, typename U> +class NestedBase { + T* buff; +}; + +template<typename T> +class NestedReplaced: public NestedBase<T, int> { +}; + +template<typename T> +class Incomplete; + +template<typename T> +class NestedContainer { + T c; +private: + NestedReplaced<T> nested; + Incomplete<T> inc; +}; + +template<typename T> +class Incomplete { + T d; +}; + +class Untemplated {}; + +template<typename T> +class Templated { + Untemplated m_untemplated; +}; + +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + * <div rustbindgen replaces="ReplacedWithoutDestructor"></div> + */ +template<typename T> +class ReplacedWithDestructor { + T* buff; + ~ReplacedWithDestructor() {}; +}; + +template<typename T> +class ReplacedWithoutDestructor { + T* buff; +}; + +template<typename T> +class ReplacedWithoutDestructorFwd; + +template<typename T> +class ShouldNotBeCopiable { + ReplacedWithoutDestructor<T> m_member; +}; + +template<typename U> +class ShouldNotBeCopiableAsWell { + ReplacedWithoutDestructorFwd<U> m_member; +}; + +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + * <div rustbindgen replaces="ReplacedWithoutDestructorFwd"></div> + */ +template<typename T> +class ReplacedWithDestructorDeclaredAfter { + T* buff; + ~ReplacedWithDestructorDeclaredAfter() {}; +}; + +template<typename T> +class TemplateWithVar { + static T var = 0; +}; diff --git a/tests/tools/run-bindgen.py b/tests/tools/run-bindgen.py index 0e3252ee..5fde6739 100755 --- a/tests/tools/run-bindgen.py +++ b/tests/tools/run-bindgen.py @@ -20,13 +20,14 @@ with open(sys.argv[2]) as f: if line.startswith(BINDGEN_FLAGS_PREFIX): flags = line.strip().split(BINDGEN_FLAGS_PREFIX)[1].split(' ') -base_command = [sys.argv[1], sys.argv[2], "-o", sys.argv[3]] +base_command = [sys.argv[1], "-o", sys.argv[3]] for line in COMMON_PRELUDE.split('\n'): flags.append("-raw-line") flags.append(line) base_command.extend(flags); +base_command.append(sys.argv[2]); subprocess.check_call(base_command, cwd=os.getcwd()) |