| mod helpers; |
| mod struct_layout; |
| |
| use self::helpers::{BlobTyBuilder, attributes}; |
| use self::struct_layout::StructLayoutTracker; |
| use aster; |
| |
| use ir::annotations::FieldAccessorKind; |
| use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind}; |
| use ir::context::{BindgenContext, ItemId}; |
| use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; |
| use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; |
| use ir::function::{Function, FunctionSig}; |
| use ir::int::IntKind; |
| use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath, |
| ItemSet}; |
| use ir::item_kind::ItemKind; |
| use ir::layout::Layout; |
| use ir::module::Module; |
| use ir::objc::ObjCInterface; |
| use ir::ty::{Type, TypeKind}; |
| use ir::var::Var; |
| |
| use std::borrow::Cow; |
| use std::cell::Cell; |
| use std::cmp; |
| use std::collections::{HashSet, VecDeque}; |
| use std::collections::hash_map::{Entry, HashMap}; |
| use std::fmt::Write; |
| use std::mem; |
| use std::ops; |
| use syntax::abi::Abi; |
| use syntax::ast; |
| use syntax::codemap::{Span, respan}; |
| use syntax::ptr::P; |
| |
| fn root_import_depth(ctx: &BindgenContext, item: &Item) -> usize { |
| if !ctx.options().enable_cxx_namespaces { |
| return 0; |
| } |
| |
| item.ancestors(ctx) |
| .filter(|id| ctx.resolve_item(*id).is_module()) |
| .fold(1, |i, _| i + 1) |
| } |
| |
| fn top_level_path(ctx: &BindgenContext, item: &Item) -> Vec<ast::Ident> { |
| let mut path = vec![ctx.rust_ident_raw("self")]; |
| |
| if ctx.options().enable_cxx_namespaces { |
| let super_ = ctx.rust_ident_raw("super"); |
| |
| for _ in 0..root_import_depth(ctx, item) { |
| path.push(super_.clone()); |
| } |
| } |
| |
| path |
| } |
| |
| fn root_import(ctx: &BindgenContext, module: &Item) -> P<ast::Item> { |
| assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up"); |
| assert!(module.is_module()); |
| |
| let mut path = top_level_path(ctx, module); |
| |
| let root = ctx.root_module().canonical_name(ctx); |
| let root_ident = ctx.rust_ident(&root); |
| path.push(root_ident); |
| |
| let use_root = aster::AstBuilder::new() |
| .item() |
| .use_() |
| .ids(path) |
| .build() |
| .build(); |
| |
| quote_item!(ctx.ext_cx(), #[allow(unused_imports)] $use_root).unwrap() |
| } |
| |
| struct CodegenResult<'a> { |
| items: Vec<P<ast::Item>>, |
| |
| /// A monotonic counter used to add stable unique id's to stuff that doesn't |
| /// need to be referenced by anything. |
| codegen_id: &'a Cell<usize>, |
| |
| /// Whether an union has been generated at least once. |
| saw_union: bool, |
| |
| /// Whether an incomplete array has been generated at least once. |
| saw_incomplete_array: bool, |
| |
| /// Whether Objective C types have been seen at least once. |
| saw_objc: bool, |
| |
| items_seen: HashSet<ItemId>, |
| /// The set of generated function/var names, needed because in C/C++ is |
| /// legal to do something like: |
| /// |
| /// ```c++ |
| /// extern "C" { |
| /// void foo(); |
| /// extern int bar; |
| /// } |
| /// |
| /// extern "C" { |
| /// void foo(); |
| /// extern int bar; |
| /// } |
| /// ``` |
| /// |
| /// Being these two different declarations. |
| functions_seen: HashSet<String>, |
| vars_seen: HashSet<String>, |
| |
| /// Used for making bindings to overloaded functions. Maps from a canonical |
| /// function name to the number of overloads we have already codegen'd for |
| /// that name. This lets us give each overload a unique suffix. |
| overload_counters: HashMap<String, u32>, |
| } |
| |
| impl<'a> CodegenResult<'a> { |
| fn new(codegen_id: &'a Cell<usize>) -> Self { |
| CodegenResult { |
| items: vec![], |
| saw_union: false, |
| saw_incomplete_array: false, |
| saw_objc: false, |
| codegen_id: codegen_id, |
| items_seen: Default::default(), |
| functions_seen: Default::default(), |
| vars_seen: Default::default(), |
| overload_counters: Default::default(), |
| } |
| } |
| |
| fn next_id(&mut self) -> usize { |
| self.codegen_id.set(self.codegen_id.get() + 1); |
| self.codegen_id.get() |
| } |
| |
| fn saw_union(&mut self) { |
| self.saw_union = true; |
| } |
| |
| fn saw_incomplete_array(&mut self) { |
| self.saw_incomplete_array = true; |
| } |
| |
| fn saw_objc(&mut self) { |
| self.saw_objc = true; |
| } |
| |
| fn seen(&self, item: ItemId) -> bool { |
| self.items_seen.contains(&item) |
| } |
| |
| fn set_seen(&mut self, item: ItemId) { |
| self.items_seen.insert(item); |
| } |
| |
| fn seen_function(&self, name: &str) -> bool { |
| self.functions_seen.contains(name) |
| } |
| |
| fn saw_function(&mut self, name: &str) { |
| self.functions_seen.insert(name.into()); |
| } |
| |
| /// Get the overload number for the given function name. Increments the |
| /// counter internally so the next time we ask for the overload for this |
| /// name, we get the incremented value, and so on. |
| fn overload_number(&mut self, name: &str) -> u32 { |
| let mut counter = |
| self.overload_counters.entry(name.into()).or_insert(0); |
| let number = *counter; |
| *counter += 1; |
| number |
| } |
| |
| fn seen_var(&self, name: &str) -> bool { |
| self.vars_seen.contains(name) |
| } |
| |
| fn saw_var(&mut self, name: &str) { |
| self.vars_seen.insert(name.into()); |
| } |
| |
| fn inner<F>(&mut self, cb: F) -> Vec<P<ast::Item>> |
| where F: FnOnce(&mut Self), |
| { |
| let mut new = Self::new(self.codegen_id); |
| |
| cb(&mut new); |
| |
| self.saw_union |= new.saw_union; |
| self.saw_incomplete_array |= new.saw_incomplete_array; |
| self.saw_objc |= new.saw_objc; |
| |
| new.items |
| } |
| } |
| |
| impl<'a> ops::Deref for CodegenResult<'a> { |
| type Target = Vec<P<ast::Item>>; |
| |
| fn deref(&self) -> &Self::Target { |
| &self.items |
| } |
| } |
| |
| impl<'a> ops::DerefMut for CodegenResult<'a> { |
| fn deref_mut(&mut self) -> &mut Self::Target { |
| &mut self.items |
| } |
| } |
| |
| struct ForeignModBuilder { |
| inner: ast::ForeignMod, |
| } |
| |
| impl ForeignModBuilder { |
| fn new(abi: Abi) -> Self { |
| ForeignModBuilder { |
| inner: ast::ForeignMod { |
| abi: abi, |
| items: vec![], |
| }, |
| } |
| } |
| |
| fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self { |
| self.inner.items.push(item); |
| self |
| } |
| |
| #[allow(dead_code)] |
| fn with_foreign_items<I>(mut self, items: I) -> Self |
| where I: IntoIterator<Item = ast::ForeignItem>, |
| { |
| self.inner.items.extend(items.into_iter()); |
| self |
| } |
| |
| fn build(self, ctx: &BindgenContext) -> P<ast::Item> { |
| use syntax::codemap::DUMMY_SP; |
| P(ast::Item { |
| ident: ctx.rust_ident(""), |
| id: ast::DUMMY_NODE_ID, |
| node: ast::ItemKind::ForeignMod(self.inner), |
| vis: ast::Visibility::Public, |
| attrs: vec![], |
| span: DUMMY_SP, |
| }) |
| } |
| } |
| |
| /// A trait to convert a rust type into a pointer, optionally const, to the same |
| /// type. |
| /// |
| /// This is done due to aster's lack of pointer builder, I guess I should PR |
| /// there. |
| trait ToPtr { |
| fn to_ptr(self, is_const: bool, span: Span) -> P<ast::Ty>; |
| } |
| |
| impl ToPtr for P<ast::Ty> { |
| fn to_ptr(self, is_const: bool, span: Span) -> Self { |
| let ty = ast::TyKind::Ptr(ast::MutTy { |
| ty: self, |
| mutbl: if is_const { |
| ast::Mutability::Immutable |
| } else { |
| ast::Mutability::Mutable |
| }, |
| }); |
| P(ast::Ty { |
| id: ast::DUMMY_NODE_ID, |
| node: ty, |
| span: span, |
| }) |
| } |
| } |
| |
| trait CodeGenerator { |
| /// Extra information from the caller. |
| type Extra; |
| |
| fn codegen<'a>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'a>, |
| whitelisted_items: &ItemSet, |
| extra: &Self::Extra); |
| } |
| |
| impl CodeGenerator for Item { |
| type Extra = (); |
| |
| fn codegen<'a>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'a>, |
| whitelisted_items: &ItemSet, |
| _extra: &()) { |
| if self.is_hidden(ctx) || result.seen(self.id()) { |
| debug!("<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \ |
| self = {:?}", |
| self); |
| return; |
| } |
| |
| debug!("<Item as CodeGenerator>::codegen: self = {:?}", self); |
| if !whitelisted_items.contains(&self.id()) { |
| // TODO(emilio, #453): Figure out what to do when this happens |
| // legitimately, we could track the opaque stuff and disable the |
| // assertion there I guess. |
| error!("Found non-whitelisted item in code generation: {:?}", self); |
| } |
| |
| result.set_seen(self.id()); |
| |
| match *self.kind() { |
| ItemKind::Module(ref module) => { |
| module.codegen(ctx, result, whitelisted_items, self); |
| } |
| ItemKind::Function(ref fun) => { |
| if ctx.options().codegen_config.functions { |
| fun.codegen(ctx, result, whitelisted_items, self); |
| } |
| } |
| ItemKind::Var(ref var) => { |
| if ctx.options().codegen_config.vars { |
| var.codegen(ctx, result, whitelisted_items, self); |
| } |
| } |
| ItemKind::Type(ref ty) => { |
| if ctx.options().codegen_config.types { |
| ty.codegen(ctx, result, whitelisted_items, self); |
| } |
| } |
| } |
| } |
| } |
| |
| impl CodeGenerator for Module { |
| type Extra = Item; |
| |
| fn codegen<'a>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'a>, |
| whitelisted_items: &ItemSet, |
| item: &Item) { |
| debug!("<Module as CodeGenerator>::codegen: item = {:?}", item); |
| |
| let codegen_self = |result: &mut CodegenResult, |
| found_any: &mut bool| { |
| for child in self.children() { |
| if whitelisted_items.contains(child) { |
| *found_any = true; |
| ctx.resolve_item(*child) |
| .codegen(ctx, result, whitelisted_items, &()); |
| } |
| } |
| |
| if item.id() == ctx.root_module() { |
| let saw_union = result.saw_union; |
| if saw_union && !ctx.options().unstable_rust { |
| utils::prepend_union_types(ctx, &mut *result); |
| } |
| if result.saw_incomplete_array { |
| utils::prepend_incomplete_array_types(ctx, &mut *result); |
| } |
| if ctx.need_bindegen_complex_type() { |
| utils::prepend_complex_type(ctx, &mut *result); |
| } |
| if result.saw_objc { |
| utils::prepend_objc_header(ctx, &mut *result); |
| } |
| } |
| }; |
| |
| if !ctx.options().enable_cxx_namespaces || |
| (self.is_inline() && !ctx.options().conservative_inline_namespaces) { |
| codegen_self(result, &mut false); |
| return; |
| } |
| |
| let mut found_any = false; |
| let inner_items = result.inner(|result| { |
| result.push(root_import(ctx, item)); |
| codegen_self(result, &mut found_any); |
| }); |
| |
| // Don't bother creating an empty module. |
| if !found_any { |
| return; |
| } |
| |
| let module = ast::ItemKind::Mod(ast::Mod { |
| inner: ctx.span(), |
| items: inner_items, |
| }); |
| |
| let name = item.canonical_name(ctx); |
| let item = aster::AstBuilder::new() |
| .item() |
| .pub_() |
| .build_item_kind(name, module); |
| |
| result.push(item); |
| } |
| } |
| |
| impl CodeGenerator for Var { |
| type Extra = Item; |
| fn codegen<'a>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'a>, |
| _whitelisted_items: &ItemSet, |
| item: &Item) { |
| use ir::var::VarType; |
| debug!("<Var as CodeGenerator>::codegen: item = {:?}", item); |
| |
| let canonical_name = item.canonical_name(ctx); |
| |
| if result.seen_var(&canonical_name) { |
| return; |
| } |
| result.saw_var(&canonical_name); |
| |
| let ty = self.ty().to_rust_ty(ctx); |
| |
| if let Some(val) = self.val() { |
| let const_item = aster::AstBuilder::new() |
| .item() |
| .pub_() |
| .const_(canonical_name) |
| .expr(); |
| let item = match *val { |
| VarType::Bool(val) => { |
| const_item.build(helpers::ast_ty::bool_expr(val)) |
| .build(ty) |
| } |
| VarType::Int(val) => { |
| const_item.build(helpers::ast_ty::int_expr(val)).build(ty) |
| } |
| VarType::String(ref bytes) => { |
| // Account the trailing zero. |
| // |
| // TODO: Here we ignore the type we just made up, probably |
| // we should refactor how the variable type and ty id work. |
| let len = bytes.len() + 1; |
| let ty = quote_ty!(ctx.ext_cx(), [u8; $len]); |
| |
| match String::from_utf8(bytes.clone()) { |
| Ok(string) => { |
| const_item.build(helpers::ast_ty::cstr_expr(string)) |
| .build(quote_ty!(ctx.ext_cx(), &'static $ty)) |
| } |
| Err(..) => { |
| const_item |
| .build(helpers::ast_ty::byte_array_expr(bytes)) |
| .build(ty) |
| } |
| } |
| } |
| VarType::Float(f) => { |
| const_item.build(helpers::ast_ty::float_expr(f)) |
| .build(ty) |
| } |
| VarType::Char(c) => { |
| const_item |
| .build(aster::AstBuilder::new().expr().lit().byte(c)) |
| .build(ty) |
| } |
| }; |
| |
| result.push(item); |
| } else { |
| let mut attrs = vec![]; |
| if let Some(mangled) = self.mangled_name() { |
| attrs.push(attributes::link_name(mangled)); |
| } else if canonical_name != self.name() { |
| attrs.push(attributes::link_name(self.name())); |
| } |
| |
| let item = ast::ForeignItem { |
| ident: ctx.rust_ident_raw(&canonical_name), |
| attrs: attrs, |
| node: ast::ForeignItemKind::Static(ty, !self.is_const()), |
| id: ast::DUMMY_NODE_ID, |
| span: ctx.span(), |
| vis: ast::Visibility::Public, |
| }; |
| |
| let item = ForeignModBuilder::new(Abi::C) |
| .with_foreign_item(item) |
| .build(ctx); |
| result.push(item); |
| } |
| } |
| } |
| |
| impl CodeGenerator for Type { |
| type Extra = Item; |
| |
| fn codegen<'a>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'a>, |
| whitelisted_items: &ItemSet, |
| item: &Item) { |
| debug!("<Type as CodeGenerator>::codegen: item = {:?}", item); |
| |
| match *self.kind() { |
| TypeKind::Void | |
| TypeKind::NullPtr | |
| TypeKind::Int(..) | |
| TypeKind::Float(..) | |
| TypeKind::Complex(..) | |
| TypeKind::Array(..) | |
| TypeKind::Pointer(..) | |
| TypeKind::BlockPointer | |
| TypeKind::Reference(..) | |
| TypeKind::TemplateInstantiation(..) | |
| TypeKind::Function(..) | |
| TypeKind::ResolvedTypeRef(..) | |
| TypeKind::Named => { |
| // These items don't need code generation, they only need to be |
| // converted to rust types in fields, arguments, and such. |
| return; |
| } |
| TypeKind::Comp(ref ci) => { |
| ci.codegen(ctx, result, whitelisted_items, item) |
| } |
| // NB: The code below will pick the correct |
| // applicable_template_args. |
| TypeKind::TemplateAlias(inner, _) | |
| TypeKind::Alias(inner) => { |
| let inner_item = ctx.resolve_item(inner); |
| let name = item.canonical_name(ctx); |
| |
| // Try to catch the common pattern: |
| // |
| // typedef struct foo { ... } foo; |
| // |
| // here. |
| // |
| if inner_item.canonical_name(ctx) == name { |
| return; |
| } |
| |
| // If this is a known named type, disallow generating anything |
| // for it too. |
| let spelling = self.name().expect("Unnamed alias?"); |
| if utils::type_from_named(ctx, spelling, inner).is_some() { |
| return; |
| } |
| |
| let mut applicable_template_args = |
| item.applicable_template_args(ctx); |
| let inner_rust_type = if item.is_opaque(ctx) { |
| applicable_template_args.clear(); |
| // Pray if there's no layout. |
| let layout = self.layout(ctx).unwrap_or_else(Layout::zero); |
| BlobTyBuilder::new(layout).build() |
| } else { |
| inner_item.to_rust_ty(ctx) |
| }; |
| |
| { |
| // FIXME(emilio): This is a workaround to avoid generating |
| // incorrect type aliases because of types that we haven't |
| // been able to resolve (because, eg, they depend on a |
| // template parameter). |
| // |
| // It's kind of a shame not generating them even when they |
| // could be referenced, but we already do the same for items |
| // with invalid template parameters, and at least this way |
| // they can be replaced, instead of generating plain invalid |
| // code. |
| let inner_canon_type = inner_item.expect_type() |
| .canonical_type(ctx); |
| if inner_canon_type.is_invalid_named_type() { |
| warn!("Item contained invalid named type, skipping: \ |
| {:?}, {:?}", |
| item, |
| inner_item); |
| return; |
| } |
| } |
| |
| let rust_name = ctx.rust_ident(&name); |
| let mut typedef = aster::AstBuilder::new().item().pub_(); |
| |
| if ctx.options().generate_comments { |
| if let Some(comment) = item.comment() { |
| typedef = typedef.attr().doc(comment); |
| } |
| } |
| |
| // We prefer using `pub use` over `pub type` because of: |
| // https://github.com/rust-lang/rust/issues/26264 |
| let simple_enum_path = match inner_rust_type.node { |
| ast::TyKind::Path(None, ref p) => { |
| if applicable_template_args.is_empty() && |
| inner_item.expect_type() |
| .canonical_type(ctx) |
| .is_enum() && |
| p.segments.iter().all(|p| p.parameters.is_none()) { |
| Some(p.clone()) |
| } else { |
| None |
| } |
| } |
| _ => None, |
| }; |
| |
| let typedef = if let Some(mut p) = simple_enum_path { |
| for ident in top_level_path(ctx, item).into_iter().rev() { |
| p.segments.insert(0, |
| ast::PathSegment { |
| identifier: ident, |
| parameters: None, |
| }); |
| } |
| typedef.use_().build(p).as_(rust_name) |
| } else { |
| let mut generics = typedef.type_(rust_name).generics(); |
| for template_arg in applicable_template_args.iter() { |
| let template_arg = ctx.resolve_type(*template_arg); |
| if template_arg.is_named() { |
| if template_arg.is_invalid_named_type() { |
| warn!("Item contained invalid template \ |
| parameter: {:?}", |
| item); |
| return; |
| } |
| generics = |
| generics.ty_param_id(template_arg.name().unwrap()); |
| } |
| } |
| generics.build().build_ty(inner_rust_type) |
| }; |
| result.push(typedef) |
| } |
| TypeKind::Enum(ref ei) => { |
| ei.codegen(ctx, result, whitelisted_items, item) |
| } |
| TypeKind::ObjCInterface(ref interface) => { |
| interface.codegen(ctx, result, whitelisted_items, item) |
| } |
| ref u @ TypeKind::UnresolvedTypeRef(..) => { |
| unreachable!("Should have been resolved after parsing {:?}!", u) |
| } |
| } |
| } |
| } |
| |
| struct Vtable<'a> { |
| item_id: ItemId, |
| #[allow(dead_code)] |
| methods: &'a [Method], |
| #[allow(dead_code)] |
| base_classes: &'a [Base], |
| } |
| |
| impl<'a> Vtable<'a> { |
| fn new(item_id: ItemId, |
| methods: &'a [Method], |
| base_classes: &'a [Base]) |
| -> Self { |
| Vtable { |
| item_id: item_id, |
| methods: methods, |
| base_classes: base_classes, |
| } |
| } |
| } |
| |
| impl<'a> CodeGenerator for Vtable<'a> { |
| type Extra = Item; |
| |
| fn codegen<'b>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'b>, |
| _whitelisted_items: &ItemSet, |
| item: &Item) { |
| assert_eq!(item.id(), self.item_id); |
| // For now, generate an empty struct, later we should generate function |
| // pointers and whatnot. |
| let mut attributes = vec![attributes::repr("C")]; |
| |
| if ctx.options().derive_default { |
| attributes.push(attributes::derives(&["Default"])) |
| } |
| |
| let vtable = aster::AstBuilder::new() |
| .item() |
| .pub_() |
| .with_attrs(attributes) |
| .struct_(self.canonical_name(ctx)) |
| .build(); |
| result.push(vtable); |
| } |
| } |
| |
| impl<'a> ItemCanonicalName for Vtable<'a> { |
| fn canonical_name(&self, ctx: &BindgenContext) -> String { |
| format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) |
| } |
| } |
| |
| impl<'a> ItemToRustTy for Vtable<'a> { |
| fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> { |
| aster::ty::TyBuilder::new().id(self.canonical_name(ctx)) |
| } |
| } |
| |
| struct Bitfield<'a> { |
| index: usize, |
| fields: Vec<&'a Field>, |
| } |
| |
| impl<'a> Bitfield<'a> { |
| fn new(index: usize, fields: Vec<&'a Field>) -> Self { |
| Bitfield { |
| index: index, |
| fields: fields, |
| } |
| } |
| |
| fn codegen_fields(self, |
| ctx: &BindgenContext, |
| fields: &mut Vec<ast::StructField>, |
| methods: &mut Vec<ast::ImplItem>) |
| -> Layout { |
| use aster::struct_field::StructFieldBuilder; |
| let mut total_width = self.fields |
| .iter() |
| .fold(0u32, |acc, f| acc + f.bitfield().unwrap()); |
| |
| if !total_width.is_power_of_two() || total_width < 8 { |
| total_width = cmp::max(8, total_width.next_power_of_two()); |
| } |
| debug_assert_eq!(total_width % 8, 0); |
| let total_width_in_bytes = total_width as usize / 8; |
| |
| let bitfield_layout = Layout::new(total_width_in_bytes, |
| total_width_in_bytes); |
| let bitfield_type = BlobTyBuilder::new(bitfield_layout).build(); |
| let field_name = format!("_bitfield_{}", self.index); |
| let field_ident = ctx.ext_cx().ident_of(&field_name); |
| let field = StructFieldBuilder::named(&field_name) |
| .pub_() |
| .build_ty(bitfield_type.clone()); |
| fields.push(field); |
| |
| |
| let mut offset = 0; |
| for field in self.fields { |
| let width = field.bitfield().unwrap(); |
| let field_name = field.name() |
| .map(ToOwned::to_owned) |
| .unwrap_or_else(|| format!("at_offset_{}", offset)); |
| |
| let field_item = ctx.resolve_item(field.ty()); |
| let field_ty_layout = field_item.kind() |
| .expect_type() |
| .layout(ctx) |
| .expect("Bitfield without layout? Gah!"); |
| |
| let field_type = field_item.to_rust_ty(ctx); |
| let int_type = BlobTyBuilder::new(field_ty_layout).build(); |
| |
| let getter_name = ctx.rust_ident(&field_name); |
| let setter_name = ctx.ext_cx() |
| .ident_of(&format!("set_{}", &field_name)); |
| let mask = ((1usize << width) - 1) << offset; |
| let prefix = ctx.trait_prefix(); |
| // The transmute is unfortunate, but it's needed for enums in |
| // bitfields. |
| let item = quote_item!(ctx.ext_cx(), |
| impl X { |
| #[inline] |
| pub fn $getter_name(&self) -> $field_type { |
| unsafe { |
| ::$prefix::mem::transmute( |
| ( |
| (self.$field_ident & |
| ($mask as $bitfield_type)) |
| >> $offset |
| ) as $int_type |
| ) |
| } |
| } |
| |
| #[inline] |
| pub fn $setter_name(&mut self, val: $field_type) { |
| self.$field_ident &= !($mask as $bitfield_type); |
| self.$field_ident |= |
| (val as $int_type as $bitfield_type << $offset) & |
| ($mask as $bitfield_type); |
| } |
| } |
| ) |
| .unwrap(); |
| |
| let items = match item.unwrap().node { |
| ast::ItemKind::Impl(_, _, _, _, _, items) => items, |
| _ => unreachable!(), |
| }; |
| |
| methods.extend(items.into_iter()); |
| offset += width; |
| } |
| |
| bitfield_layout |
| } |
| } |
| |
| impl CodeGenerator for CompInfo { |
| type Extra = Item; |
| |
| fn codegen<'a>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'a>, |
| whitelisted_items: &ItemSet, |
| item: &Item) { |
| use aster::struct_field::StructFieldBuilder; |
| |
| debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item); |
| |
| // Don't output classes with template parameters that aren't types, and |
| // also don't output template specializations, neither total or partial. |
| if self.has_non_type_template_params() { |
| return; |
| } |
| |
| let applicable_template_args = item.applicable_template_args(ctx); |
| |
| // generate tuple struct if struct or union is a forward declaration, |
| // skip for now if template parameters are needed. |
| if self.is_forward_declaration() && |
| applicable_template_args.is_empty() { |
| let struct_name = item.canonical_name(ctx); |
| let struct_name = ctx.rust_ident_raw(&struct_name); |
| let tuple_struct = quote_item!(ctx.ext_cx(), |
| #[repr(C)] |
| #[derive(Debug, Copy, Clone)] |
| pub struct $struct_name([u8; 0]); |
| ) |
| .unwrap(); |
| result.push(tuple_struct); |
| return; |
| } |
| |
| if self.is_template_specialization() { |
| let layout = item.kind().expect_type().layout(ctx); |
| |
| if let Some(layout) = layout { |
| let fn_name = format!("__bindgen_test_layout_template_{}", |
| result.next_id()); |
| let fn_name = ctx.rust_ident_raw(&fn_name); |
| let ident = item.to_rust_ty(ctx); |
| let prefix = ctx.trait_prefix(); |
| let size_of_expr = quote_expr!(ctx.ext_cx(), |
| ::$prefix::mem::size_of::<$ident>()); |
| let align_of_expr = quote_expr!(ctx.ext_cx(), |
| ::$prefix::mem::align_of::<$ident>()); |
| let size = layout.size; |
| let align = layout.align; |
| let item = quote_item!(ctx.ext_cx(), |
| #[test] |
| fn $fn_name() { |
| assert_eq!($size_of_expr, $size, |
| concat!("Size of template specialization: ", stringify!($ident))); |
| assert_eq!($align_of_expr, $align, |
| concat!("Alignment of template specialization: ", stringify!($ident))); |
| }) |
| .unwrap(); |
| result.push(item); |
| } |
| return; |
| } |
| |
| let mut attributes = vec![]; |
| let mut needs_clone_impl = false; |
| let mut needs_default_impl = false; |
| if ctx.options().generate_comments { |
| if let Some(comment) = item.comment() { |
| attributes.push(attributes::doc(comment)); |
| } |
| } |
| if self.packed() { |
| attributes.push(attributes::repr_list(&["C", "packed"])); |
| } else { |
| attributes.push(attributes::repr("C")); |
| } |
| |
| let is_union = self.kind() == CompKind::Union; |
| let mut derives = vec![]; |
| if item.can_derive_debug(ctx, ()) { |
| derives.push("Debug"); |
| } |
| |
| if item.can_derive_default(ctx, ()) { |
| derives.push("Default"); |
| } else { |
| needs_default_impl = ctx.options().derive_default; |
| } |
| |
| if item.can_derive_copy(ctx, ()) && |
| !item.annotations().disallow_copy() { |
| derives.push("Copy"); |
| if !applicable_template_args.is_empty() { |
| // FIXME: This requires extra logic if you have a big array in a |
| // templated struct. The reason for this is that the magic: |
| // fn clone(&self) -> Self { *self } |
| // doesn't work for templates. |
| // |
| // It's not hard to fix though. |
| derives.push("Clone"); |
| } else { |
| needs_clone_impl = true; |
| } |
| } |
| |
| if !derives.is_empty() { |
| attributes.push(attributes::derives(&derives)) |
| } |
| |
| let mut template_args_used = |
| vec![false; applicable_template_args.len()]; |
| let canonical_name = item.canonical_name(ctx); |
| let builder = if is_union && ctx.options().unstable_rust { |
| aster::AstBuilder::new() |
| .item() |
| .pub_() |
| .with_attrs(attributes) |
| .union_(&canonical_name) |
| } else { |
| aster::AstBuilder::new() |
| .item() |
| .pub_() |
| .with_attrs(attributes) |
| .struct_(&canonical_name) |
| }; |
| |
| // Generate the vtable from the method list if appropriate. |
| // |
| // TODO: I don't know how this could play with virtual methods that are |
| // not in the list of methods found by us, we'll see. Also, could the |
| // order of the vtable pointers vary? |
| // |
| // FIXME: Once we generate proper vtables, we need to codegen the |
| // vtable, but *not* generate a field for it in the case that |
| // needs_explicit_vtable is false but has_vtable is true. |
| // |
| // Also, we need to generate the vtable in such a way it "inherits" from |
| // the parent too. |
| let mut fields = vec![]; |
| let mut struct_layout = StructLayoutTracker::new(ctx, self); |
| if self.needs_explicit_vtable(ctx) { |
| let vtable = |
| Vtable::new(item.id(), self.methods(), self.base_members()); |
| vtable.codegen(ctx, result, whitelisted_items, item); |
| |
| let vtable_type = vtable.to_rust_ty(ctx).to_ptr(true, ctx.span()); |
| |
| let vtable_field = StructFieldBuilder::named("vtable_") |
| .pub_() |
| .build_ty(vtable_type); |
| |
| struct_layout.saw_vtable(); |
| |
| fields.push(vtable_field); |
| } |
| |
| for (i, base) in self.base_members().iter().enumerate() { |
| // Virtual bases are already taken into account by the vtable |
| // pointer. |
| // |
| // FIXME(emilio): Is this always right? |
| if base.is_virtual() { |
| continue; |
| } |
| |
| let base_ty = ctx.resolve_type(base.ty); |
| // NB: We won't include unsized types in our base chain because they |
| // would contribute to our size given the dummy field we insert for |
| // unsized types. |
| if base_ty.is_unsized(ctx) { |
| continue; |
| } |
| |
| for (i, ty_id) in applicable_template_args.iter().enumerate() { |
| let template_arg_ty = ctx.resolve_type(*ty_id); |
| if base_ty.signature_contains_named_type(ctx, template_arg_ty) { |
| template_args_used[i] = true; |
| } |
| } |
| |
| let inner = base.ty.to_rust_ty(ctx); |
| let field_name = if i == 0 { |
| "_base".into() |
| } else { |
| format!("_base_{}", i) |
| }; |
| |
| struct_layout.saw_base(base_ty); |
| |
| let field = StructFieldBuilder::named(field_name) |
| .pub_() |
| .build_ty(inner); |
| fields.push(field); |
| } |
| if is_union { |
| result.saw_union(); |
| } |
| |
| let layout = item.kind().expect_type().layout(ctx); |
| |
| let mut current_bitfield_width = None; |
| let mut current_bitfield_layout: Option<Layout> = None; |
| let mut current_bitfield_fields = vec![]; |
| let mut bitfield_count = 0; |
| let struct_fields = self.fields(); |
| let fields_should_be_private = item.annotations() |
| .private_fields() |
| .unwrap_or(false); |
| let struct_accessor_kind = item.annotations() |
| .accessor_kind() |
| .unwrap_or(FieldAccessorKind::None); |
| |
| let mut methods = vec![]; |
| let mut anonymous_field_count = 0; |
| for field in struct_fields { |
| debug_assert_eq!(current_bitfield_width.is_some(), |
| current_bitfield_layout.is_some()); |
| debug_assert_eq!(current_bitfield_width.is_some(), |
| !current_bitfield_fields.is_empty()); |
| |
| let field_ty = ctx.resolve_type(field.ty()); |
| |
| // Try to catch a bitfield contination early. |
| if let (Some(ref mut bitfield_width), Some(width)) = |
| (current_bitfield_width, field.bitfield()) { |
| let layout = current_bitfield_layout.unwrap(); |
| debug!("Testing bitfield continuation {} {} {:?}", |
| *bitfield_width, |
| width, |
| layout); |
| if *bitfield_width + width <= (layout.size * 8) as u32 { |
| *bitfield_width += width; |
| current_bitfield_fields.push(field); |
| continue; |
| } |
| } |
| |
| // Flush the current bitfield. |
| if current_bitfield_width.is_some() { |
| debug_assert!(!current_bitfield_fields.is_empty()); |
| let bitfield_fields = |
| mem::replace(&mut current_bitfield_fields, vec![]); |
| bitfield_count += 1; |
| let bitfield_layout = Bitfield::new(bitfield_count, |
| bitfield_fields) |
| .codegen_fields(ctx, &mut fields, &mut methods); |
| |
| struct_layout.saw_bitfield(bitfield_layout); |
| |
| current_bitfield_width = None; |
| current_bitfield_layout = None; |
| } |
| debug_assert!(current_bitfield_fields.is_empty()); |
| |
| if let Some(width) = field.bitfield() { |
| let layout = field_ty.layout(ctx) |
| .expect("Bitfield type without layout?"); |
| current_bitfield_width = Some(width); |
| current_bitfield_layout = Some(layout); |
| current_bitfield_fields.push(field); |
| continue; |
| } |
| |
| for (i, ty_id) in applicable_template_args.iter().enumerate() { |
| let template_arg = ctx.resolve_type(*ty_id); |
| if field_ty.signature_contains_named_type(ctx, template_arg) { |
| template_args_used[i] = true; |
| } |
| } |
| |
| let ty = field.ty().to_rust_ty(ctx); |
| |
| // NB: In unstable rust we use proper `union` types. |
| let ty = if is_union && !ctx.options().unstable_rust { |
| if ctx.options().enable_cxx_namespaces { |
| quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>) |
| } else { |
| quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) |
| } |
| } else if let Some(item) = |
| field_ty.is_incomplete_array(ctx) { |
| result.saw_incomplete_array(); |
| |
| let inner = item.to_rust_ty(ctx); |
| |
| if ctx.options().enable_cxx_namespaces { |
| quote_ty!(ctx.ext_cx(), root::__IncompleteArrayField<$inner>) |
| } else { |
| quote_ty!(ctx.ext_cx(), __IncompleteArrayField<$inner>) |
| } |
| } else { |
| ty |
| }; |
| |
| let mut attrs = vec![]; |
| if ctx.options().generate_comments { |
| if let Some(comment) = field.comment() { |
| attrs.push(attributes::doc(comment)); |
| } |
| } |
| let field_name = match field.name() { |
| Some(name) => ctx.rust_mangle(name).into_owned(), |
| None => { |
| anonymous_field_count += 1; |
| format!("__bindgen_anon_{}", anonymous_field_count) |
| } |
| }; |
| |
| if let Some(padding_field) = |
| struct_layout.pad_field(&field_name, field_ty, field.offset()) { |
| fields.push(padding_field); |
| } |
| |
| let is_private = field.annotations() |
| .private_fields() |
| .unwrap_or(fields_should_be_private); |
| |
| let accessor_kind = field.annotations() |
| .accessor_kind() |
| .unwrap_or(struct_accessor_kind); |
| |
| let mut field = StructFieldBuilder::named(&field_name); |
| |
| if !is_private { |
| field = field.pub_(); |
| } |
| |
| let field = field.with_attrs(attrs) |
| .build_ty(ty.clone()); |
| |
| fields.push(field); |
| |
| // TODO: Factor the following code out, please! |
| if accessor_kind == FieldAccessorKind::None { |
| continue; |
| } |
| |
| let getter_name = |
| ctx.rust_ident_raw(&format!("get_{}", field_name)); |
| let mutable_getter_name = |
| ctx.rust_ident_raw(&format!("get_{}_mut", field_name)); |
| let field_name = ctx.rust_ident_raw(&field_name); |
| |
| let accessor_methods_impl = match accessor_kind { |
| FieldAccessorKind::None => unreachable!(), |
| FieldAccessorKind::Regular => { |
| quote_item!(ctx.ext_cx(), |
| impl X { |
| #[inline] |
| pub fn $getter_name(&self) -> &$ty { |
| &self.$field_name |
| } |
| |
| #[inline] |
| pub fn $mutable_getter_name(&mut self) -> &mut $ty { |
| &mut self.$field_name |
| } |
| } |
| ) |
| } |
| FieldAccessorKind::Unsafe => { |
| quote_item!(ctx.ext_cx(), |
| impl X { |
| #[inline] |
| pub unsafe fn $getter_name(&self) -> &$ty { |
| &self.$field_name |
| } |
| |
| #[inline] |
| pub unsafe fn $mutable_getter_name(&mut self) |
| -> &mut $ty { |
| &mut self.$field_name |
| } |
| } |
| ) |
| } |
| FieldAccessorKind::Immutable => { |
| quote_item!(ctx.ext_cx(), |
| impl X { |
| #[inline] |
| pub fn $getter_name(&self) -> &$ty { |
| &self.$field_name |
| } |
| } |
| ) |
| } |
| }; |
| |
| match accessor_methods_impl.unwrap().node { |
| ast::ItemKind::Impl(_, _, _, _, _, ref items) => { |
| methods.extend(items.clone()) |
| } |
| _ => unreachable!(), |
| } |
| } |
| |
| // Flush the last bitfield if any. |
| // |
| // FIXME: Reduce duplication with the loop above. |
| // FIXME: May need to pass current_bitfield_layout too. |
| if current_bitfield_width.is_some() { |
| debug_assert!(!current_bitfield_fields.is_empty()); |
| let bitfield_fields = mem::replace(&mut current_bitfield_fields, |
| vec![]); |
| bitfield_count += 1; |
| let bitfield_layout = Bitfield::new(bitfield_count, |
| bitfield_fields) |
| .codegen_fields(ctx, &mut fields, &mut methods); |
| |
| struct_layout.saw_bitfield(bitfield_layout); |
| } |
| debug_assert!(current_bitfield_fields.is_empty()); |
| |
| if is_union && !ctx.options().unstable_rust { |
| let layout = layout.expect("Unable to get layout information?"); |
| let ty = BlobTyBuilder::new(layout).build(); |
| let field = StructFieldBuilder::named("bindgen_union_field") |
| .pub_() |
| .build_ty(ty); |
| |
| struct_layout.saw_union(layout); |
| |
| fields.push(field); |
| } |
| |
| // Yeah, sorry about that. |
| if item.is_opaque(ctx) { |
| fields.clear(); |
| methods.clear(); |
| for i in 0..template_args_used.len() { |
| template_args_used[i] = false; |
| } |
| |
| match layout { |
| Some(l) => { |
| let ty = BlobTyBuilder::new(l).build(); |
| let field = |
| StructFieldBuilder::named("_bindgen_opaque_blob") |
| .pub_() |
| .build_ty(ty); |
| fields.push(field); |
| } |
| None => { |
| warn!("Opaque type without layout! Expect dragons!"); |
| } |
| } |
| } else if !is_union && !self.is_unsized(ctx) { |
| if let Some(padding_field) = |
| layout.and_then(|layout| struct_layout.pad_struct(layout)) { |
| fields.push(padding_field); |
| } |
| |
| if let Some(align_field) = |
| layout.and_then(|layout| struct_layout.align_struct(layout)) { |
| fields.push(align_field); |
| } |
| } |
| |
| // C requires every struct to be addressable, so what C compilers do is |
| // making the struct 1-byte sized. |
| // |
| // NOTE: This check is conveniently here to avoid the dummy fields we |
| // may add for unused template parameters. |
| if self.is_unsized(ctx) { |
| let ty = BlobTyBuilder::new(Layout::new(1, 1)).build(); |
| let field = StructFieldBuilder::named("_address") |
| .pub_() |
| .build_ty(ty); |
| fields.push(field); |
| } |
| |
| // Append any extra template arguments that nobody has used so far. |
| for (i, ty) in applicable_template_args.iter().enumerate() { |
| if !template_args_used[i] { |
| let name = ctx.resolve_type(*ty).name().unwrap(); |
| let ident = ctx.rust_ident(name); |
| let prefix = ctx.trait_prefix(); |
| let phantom = quote_ty!(ctx.ext_cx(), |
| ::$prefix::marker::PhantomData<$ident>); |
| let field = StructFieldBuilder::named(format!("_phantom_{}", |
| i)) |
| .pub_() |
| .build_ty(phantom); |
| fields.push(field) |
| } |
| } |
| |
| |
| let mut generics = aster::AstBuilder::new().generics(); |
| for template_arg in applicable_template_args.iter() { |
| // Take into account that here only arrive named types, not |
| // template specialisations that would need to be |
| // instantiated. |
| // |
| // TODO: Add template args from the parent, here and in |
| // `to_rust_ty`!! |
| let template_arg = ctx.resolve_type(*template_arg); |
| generics = generics.ty_param_id(template_arg.name().unwrap()); |
| } |
| |
| let generics = generics.build(); |
| |
| let rust_struct = builder.with_generics(generics.clone()) |
| .with_fields(fields) |
| .build(); |
| result.push(rust_struct); |
| |
| // Generate the inner types and all that stuff. |
| // |
| // TODO: In the future we might want to be smart, and use nested |
| // modules, and whatnot. |
| for ty in self.inner_types() { |
| let child_item = ctx.resolve_item(*ty); |
| // assert_eq!(child_item.parent_id(), item.id()); |
| child_item.codegen(ctx, result, whitelisted_items, &()); |
| } |
| |
| // NOTE: Some unexposed attributes (like alignment attributes) may |
| // affect layout, so we're bad and pray to the gods for avoid sending |
| // all the tests to shit when parsing things like max_align_t. |
| if self.found_unknown_attr() { |
| warn!("Type {} has an unkown attribute that may affect layout", |
| canonical_name); |
| } |
| |
| if applicable_template_args.is_empty() { |
| for var in self.inner_vars() { |
| ctx.resolve_item(*var) |
| .codegen(ctx, result, whitelisted_items, &()); |
| } |
| |
| if let Some(layout) = layout { |
| let fn_name = format!("bindgen_test_layout_{}", canonical_name); |
| let fn_name = ctx.rust_ident_raw(&fn_name); |
| let type_name = ctx.rust_ident_raw(&canonical_name); |
| let prefix = ctx.trait_prefix(); |
| let size_of_expr = quote_expr!(ctx.ext_cx(), |
| ::$prefix::mem::size_of::<$type_name>()); |
| let align_of_expr = quote_expr!(ctx.ext_cx(), |
| ::$prefix::mem::align_of::<$type_name>()); |
| let size = layout.size; |
| let align = layout.align; |
| |
| let check_struct_align = if align > mem::size_of::<*mut ()>() { |
| // FIXME when [RFC 1358](https://github.com/rust-lang/rust/issues/33626) ready |
| None |
| } else { |
| quote_item!(ctx.ext_cx(), |
| assert_eq!($align_of_expr, |
| $align, |
| concat!("Alignment of ", stringify!($type_name))); |
| ) |
| }; |
| |
| // FIXME when [issue #465](https://github.com/servo/rust-bindgen/issues/465) ready |
| let too_many_base_vtables = self.base_members() |
| .iter() |
| .filter(|base| { |
| ctx.resolve_type(base.ty).has_vtable(ctx) |
| }) |
| .count() > 1; |
| |
| let should_skip_field_offset_checks = item.is_opaque(ctx) || |
| too_many_base_vtables; |
| |
| let check_field_offset = if should_skip_field_offset_checks { |
| None |
| } else { |
| let asserts = self.fields() |
| .iter() |
| .filter(|field| field.bitfield().is_none()) |
| .flat_map(|field| { |
| field.name().and_then(|name| { |
| field.offset().and_then(|offset| { |
| let field_offset = offset / 8; |
| let field_name = ctx.rust_ident(name); |
| |
| quote_item!(ctx.ext_cx(), |
| assert_eq!(unsafe { &(*(0 as *const $type_name)).$field_name as *const _ as usize }, |
| $field_offset, |
| concat!("Alignment of field: ", stringify!($type_name), "::", stringify!($field_name))); |
| ) |
| }) |
| }) |
| }).collect::<Vec<P<ast::Item>>>(); |
| |
| Some(asserts) |
| }; |
| |
| let item = quote_item!(ctx.ext_cx(), |
| #[test] |
| fn $fn_name() { |
| assert_eq!($size_of_expr, |
| $size, |
| concat!("Size of: ", stringify!($type_name))); |
| |
| $check_struct_align |
| $check_field_offset |
| }) |
| .unwrap(); |
| result.push(item); |
| } |
| |
| let mut method_names = Default::default(); |
| if ctx.options().codegen_config.methods { |
| for method in self.methods() { |
| assert!(method.kind() != MethodKind::Constructor); |
| method.codegen_method(ctx, |
| &mut methods, |
| &mut method_names, |
| result, |
| whitelisted_items, |
| self); |
| } |
| } |
| |
| if ctx.options().codegen_config.constructors { |
| for sig in self.constructors() { |
| Method::new(MethodKind::Constructor, |
| *sig, |
| /* const */ |
| false) |
| .codegen_method(ctx, |
| &mut methods, |
| &mut method_names, |
| result, |
| whitelisted_items, |
| self); |
| } |
| } |
| } |
| |
| // NB: We can't use to_rust_ty here since for opaque types this tries to |
| // use the specialization knowledge to generate a blob field. |
| let ty_for_impl = aster::AstBuilder::new() |
| .ty() |
| .path() |
| .segment(&canonical_name) |
| .with_generics(generics.clone()) |
| .build() |
| .build(); |
| |
| if needs_clone_impl { |
| let impl_ = quote_item!(ctx.ext_cx(), |
| impl X { |
| fn clone(&self) -> Self { *self } |
| } |
| ); |
| |
| let impl_ = match impl_.unwrap().node { |
| ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), |
| _ => unreachable!(), |
| }; |
| |
| let clone_impl = aster::AstBuilder::new() |
| .item() |
| .impl_() |
| .trait_() |
| .id("Clone") |
| .build() |
| .with_generics(generics.clone()) |
| .with_items(impl_) |
| .build_ty(ty_for_impl.clone()); |
| |
| result.push(clone_impl); |
| } |
| |
| if needs_default_impl { |
| let prefix = ctx.trait_prefix(); |
| let impl_ = quote_item!(ctx.ext_cx(), |
| impl X { |
| fn default() -> Self { unsafe { ::$prefix::mem::zeroed() } } |
| } |
| ); |
| |
| let impl_ = match impl_.unwrap().node { |
| ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), |
| _ => unreachable!(), |
| }; |
| |
| let default_impl = aster::AstBuilder::new() |
| .item() |
| .impl_() |
| .trait_() |
| .id("Default") |
| .build() |
| .with_generics(generics.clone()) |
| .with_items(impl_) |
| .build_ty(ty_for_impl.clone()); |
| |
| result.push(default_impl); |
| } |
| |
| if !methods.is_empty() { |
| let methods = aster::AstBuilder::new() |
| .item() |
| .impl_() |
| .with_generics(generics) |
| .with_items(methods) |
| .build_ty(ty_for_impl); |
| result.push(methods); |
| } |
| } |
| } |
| |
| trait MethodCodegen { |
| fn codegen_method<'a>(&self, |
| ctx: &BindgenContext, |
| methods: &mut Vec<ast::ImplItem>, |
| method_names: &mut HashMap<String, usize>, |
| result: &mut CodegenResult<'a>, |
| whitelisted_items: &ItemSet, |
| parent: &CompInfo); |
| } |
| |
| impl MethodCodegen for Method { |
| fn codegen_method<'a>(&self, |
| ctx: &BindgenContext, |
| methods: &mut Vec<ast::ImplItem>, |
| method_names: &mut HashMap<String, usize>, |
| result: &mut CodegenResult<'a>, |
| whitelisted_items: &ItemSet, |
| _parent: &CompInfo) { |
| if self.is_virtual() { |
| return; // FIXME |
| } |
| // First of all, output the actual function. |
| let function_item = ctx.resolve_item(self.signature()); |
| function_item.codegen(ctx, result, whitelisted_items, &()); |
| |
| let function = function_item.expect_function(); |
| let signature_item = ctx.resolve_item(function.signature()); |
| let mut name = match self.kind() { |
| MethodKind::Constructor => "new".into(), |
| _ => function.name().to_owned(), |
| }; |
| |
| let signature = match *signature_item.expect_type().kind() { |
| TypeKind::Function(ref sig) => sig, |
| _ => panic!("How in the world?"), |
| }; |
| |
| // Do not generate variadic methods, since rust does not allow |
| // implementing them, and we don't do a good job at it anyway. |
| if signature.is_variadic() { |
| return; |
| } |
| |
| let count = { |
| let mut count = method_names.entry(name.clone()) |
| .or_insert(0); |
| *count += 1; |
| *count - 1 |
| }; |
| |
| if count != 0 { |
| name.push_str(&count.to_string()); |
| } |
| |
| let function_name = function_item.canonical_name(ctx); |
| let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item) |
| .unwrap(); |
| if !self.is_static() && !self.is_constructor() { |
| let mutability = if self.is_const() { |
| ast::Mutability::Immutable |
| } else { |
| ast::Mutability::Mutable |
| }; |
| |
| assert!(!fndecl.inputs.is_empty()); |
| |
| // FIXME: use aster here. |
| fndecl.inputs[0] = ast::Arg { |
| ty: P(ast::Ty { |
| id: ast::DUMMY_NODE_ID, |
| node: ast::TyKind::Rptr(None, ast::MutTy { |
| ty: P(ast::Ty { |
| id: ast::DUMMY_NODE_ID, |
| node: ast::TyKind::ImplicitSelf, |
| span: ctx.span() |
| }), |
| mutbl: mutability, |
| }), |
| span: ctx.span(), |
| }), |
| pat: P(ast::Pat { |
| id: ast::DUMMY_NODE_ID, |
| node: ast::PatKind::Ident( |
| ast::BindingMode::ByValue(ast::Mutability::Immutable), |
| respan(ctx.span(), ctx.ext_cx().ident_of("self")), |
| None |
| ), |
| span: ctx.span(), |
| }), |
| id: ast::DUMMY_NODE_ID, |
| }; |
| } |
| |
| // If it's a constructor, we always return `Self`, and we inject the |
| // "this" parameter, so there's no need to ask the user for it. |
| // |
| // Note that constructors in Clang are represented as functions with |
| // return-type = void. |
| if self.is_constructor() { |
| fndecl.inputs.remove(0); |
| fndecl.output = ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), |
| Self)); |
| } |
| |
| let sig = ast::MethodSig { |
| unsafety: ast::Unsafety::Unsafe, |
| abi: Abi::Rust, |
| decl: P(fndecl), |
| generics: ast::Generics::default(), |
| constness: respan(ctx.span(), ast::Constness::NotConst), |
| }; |
| |
| let mut exprs = helpers::ast_ty::arguments_from_signature(&signature, |
| ctx); |
| |
| let mut stmts = vec![]; |
| |
| // If it's a constructor, we need to insert an extra parameter with a |
| // variable called `__bindgen_tmp` we're going to create. |
| if self.is_constructor() { |
| let prefix = ctx.trait_prefix(); |
| let tmp_variable_decl = |
| quote_stmt!(ctx.ext_cx(), |
| let mut __bindgen_tmp = ::$prefix::mem::uninitialized()) |
| .unwrap(); |
| stmts.push(tmp_variable_decl); |
| exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp); |
| } else if !self.is_static() { |
| assert!(!exprs.is_empty()); |
| exprs[0] = if self.is_const() { |
| quote_expr!(ctx.ext_cx(), &*self) |
| } else { |
| quote_expr!(ctx.ext_cx(), &mut *self) |
| }; |
| }; |
| |
| let call = aster::expr::ExprBuilder::new() |
| .call() |
| .id(function_name) |
| .with_args(exprs) |
| .build(); |
| |
| stmts.push(ast::Stmt { |
| id: ast::DUMMY_NODE_ID, |
| node: ast::StmtKind::Expr(call), |
| span: ctx.span(), |
| }); |
| |
| if self.is_constructor() { |
| stmts.push(quote_stmt!(ctx.ext_cx(), __bindgen_tmp).unwrap()); |
| } |
| |
| let block = ast::Block { |
| stmts: stmts, |
| id: ast::DUMMY_NODE_ID, |
| rules: ast::BlockCheckMode::Default, |
| span: ctx.span(), |
| }; |
| |
| let mut attrs = vec![]; |
| attrs.push(attributes::inline()); |
| |
| let item = ast::ImplItem { |
| id: ast::DUMMY_NODE_ID, |
| ident: ctx.rust_ident(&name), |
| vis: ast::Visibility::Public, |
| attrs: attrs, |
| node: ast::ImplItemKind::Method(sig, P(block)), |
| defaultness: ast::Defaultness::Final, |
| span: ctx.span(), |
| }; |
| |
| methods.push(item); |
| } |
| } |
| |
| /// A helper type to construct enums, either bitfield ones or rust-style ones. |
| enum EnumBuilder<'a> { |
| Rust(aster::item::ItemEnumBuilder<aster::invoke::Identity>), |
| Bitfield { |
| canonical_name: &'a str, |
| aster: P<ast::Item>, |
| }, |
| Consts { aster: P<ast::Item> }, |
| } |
| |
| impl<'a> EnumBuilder<'a> { |
| /// Create a new enum given an item builder, a canonical name, a name for |
| /// the representation, and whether it should be represented as a rust enum. |
| fn new(aster: aster::item::ItemBuilder<aster::invoke::Identity>, |
| name: &'a str, |
| repr: P<ast::Ty>, |
| bitfield_like: bool, |
| constify: bool) |
| -> Self { |
| if bitfield_like { |
| EnumBuilder::Bitfield { |
| canonical_name: name, |
| aster: aster.tuple_struct(name) |
| .field() |
| .pub_() |
| .build_ty(repr) |
| .build(), |
| } |
| } else if constify { |
| EnumBuilder::Consts { |
| aster: aster.type_(name).build_ty(repr), |
| } |
| } else { |
| EnumBuilder::Rust(aster.enum_(name)) |
| } |
| } |
| |
| /// Add a variant to this enum. |
| fn with_variant<'b>(self, |
| ctx: &BindgenContext, |
| variant: &EnumVariant, |
| mangling_prefix: Option<&String>, |
| rust_ty: P<ast::Ty>, |
| result: &mut CodegenResult<'b>) |
| -> Self { |
| let variant_name = ctx.rust_mangle(variant.name()); |
| let expr = aster::AstBuilder::new().expr(); |
| let expr = match variant.val() { |
| EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), |
| EnumVariantValue::Unsigned(v) => expr.uint(v), |
| }; |
| |
| match self { |
| EnumBuilder::Rust(b) => { |
| EnumBuilder::Rust(b.with_variant_(ast::Variant_ { |
| name: ctx.rust_ident(&*variant_name), |
| attrs: vec![], |
| data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), |
| disr_expr: Some(expr), |
| })) |
| } |
| EnumBuilder::Bitfield { canonical_name, .. } => { |
| let constant_name = match mangling_prefix { |
| Some(prefix) => { |
| Cow::Owned(format!("{}_{}", prefix, variant_name)) |
| } |
| None => variant_name, |
| }; |
| |
| let constant = aster::AstBuilder::new() |
| .item() |
| .pub_() |
| .const_(&*constant_name) |
| .expr() |
| .call() |
| .id(canonical_name) |
| .arg() |
| .build(expr) |
| .build() |
| .build(rust_ty); |
| result.push(constant); |
| self |
| } |
| EnumBuilder::Consts { .. } => { |
| let constant_name = match mangling_prefix { |
| Some(prefix) => { |
| Cow::Owned(format!("{}_{}", prefix, variant_name)) |
| } |
| None => variant_name, |
| }; |
| |
| let constant = aster::AstBuilder::new() |
| .item() |
| .pub_() |
| .const_(&*constant_name) |
| .expr() |
| .build(expr) |
| .build(rust_ty); |
| |
| result.push(constant); |
| self |
| } |
| } |
| } |
| |
| fn build<'b>(self, |
| ctx: &BindgenContext, |
| rust_ty: P<ast::Ty>, |
| result: &mut CodegenResult<'b>) |
| -> P<ast::Item> { |
| match self { |
| EnumBuilder::Rust(b) => b.build(), |
| EnumBuilder::Bitfield { canonical_name, aster } => { |
| let rust_ty_name = ctx.rust_ident_raw(canonical_name); |
| let prefix = ctx.trait_prefix(); |
| |
| let impl_ = quote_item!(ctx.ext_cx(), |
| impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty { |
| type Output = Self; |
| |
| #[inline] |
| fn bitor(self, other: Self) -> Self { |
| $rust_ty_name(self.0 | other.0) |
| } |
| } |
| ) |
| .unwrap(); |
| |
| result.push(impl_); |
| aster |
| } |
| EnumBuilder::Consts { aster, .. } => aster, |
| } |
| } |
| } |
| |
| impl CodeGenerator for Enum { |
| type Extra = Item; |
| |
| fn codegen<'a>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'a>, |
| _whitelisted_items: &ItemSet, |
| item: &Item) { |
| debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item); |
| |
| let name = item.canonical_name(ctx); |
| let enum_ty = item.expect_type(); |
| let layout = enum_ty.layout(ctx); |
| |
| let repr = self.repr().map(|repr| ctx.resolve_type(repr)); |
| let repr = match repr { |
| Some(repr) => { |
| match *repr.canonical_type(ctx).kind() { |
| TypeKind::Int(int_kind) => int_kind, |
| _ => panic!("Unexpected type as enum repr"), |
| } |
| } |
| None => { |
| warn!("Guessing type of enum! Forward declarations of enums \ |
| shouldn't be legal!"); |
| IntKind::Int |
| } |
| }; |
| |
| let signed = repr.is_signed(); |
| let size = layout.map(|l| l.size) |
| .or_else(|| repr.known_size()) |
| .unwrap_or(0); |
| |
| let repr_name = match (signed, size) { |
| (true, 1) => "i8", |
| (false, 1) => "u8", |
| (true, 2) => "i16", |
| (false, 2) => "u16", |
| (true, 4) => "i32", |
| (false, 4) => "u32", |
| (true, 8) => "i64", |
| (false, 8) => "u64", |
| _ => { |
| warn!("invalid enum decl: signed: {}, size: {}", signed, size); |
| "i32" |
| } |
| }; |
| |
| let mut builder = aster::AstBuilder::new().item().pub_(); |
| |
| // FIXME(emilio): These should probably use the path so it can |
| // disambiguate between namespaces, just like is_opaque etc. |
| let is_bitfield = { |
| ctx.options().bitfield_enums.matches(&name) || |
| (enum_ty.name().is_none() && |
| self.variants() |
| .iter() |
| .any(|v| ctx.options().bitfield_enums.matches(&v.name()))) |
| }; |
| |
| let is_constified_enum = { |
| ctx.options().constified_enums.matches(&name) || |
| (enum_ty.name().is_none() && |
| self.variants() |
| .iter() |
| .any(|v| ctx.options().constified_enums.matches(&v.name()))) |
| }; |
| |
| let is_rust_enum = !is_bitfield && !is_constified_enum; |
| |
| // FIXME: Rust forbids repr with empty enums. Remove this condition when |
| // this is allowed. |
| // |
| // TODO(emilio): Delegate this to the builders? |
| if is_rust_enum { |
| if !self.variants().is_empty() { |
| builder = builder.with_attr(attributes::repr(repr_name)); |
| } |
| } else if is_bitfield { |
| builder = builder.with_attr(attributes::repr("C")); |
| } |
| |
| if ctx.options().generate_comments { |
| if let Some(comment) = item.comment() { |
| builder = builder.with_attr(attributes::doc(comment)); |
| } |
| } |
| |
| if !is_constified_enum { |
| let derives = attributes::derives(&["Debug", |
| "Copy", |
| "Clone", |
| "PartialEq", |
| "Eq", |
| "Hash"]); |
| |
| builder = builder.with_attr(derives); |
| } |
| |
| fn add_constant<'a>(enum_: &Type, |
| // Only to avoid recomputing every time. |
| enum_canonical_name: &str, |
| // May be the same as "variant" if it's because the |
| // enum is unnamed and we still haven't seen the |
| // value. |
| variant_name: &str, |
| referenced_name: &str, |
| enum_rust_ty: P<ast::Ty>, |
| result: &mut CodegenResult<'a>) { |
| let constant_name = if enum_.name().is_some() { |
| format!("{}_{}", enum_canonical_name, variant_name) |
| } else { |
| variant_name.into() |
| }; |
| |
| let constant = aster::AstBuilder::new() |
| .item() |
| .pub_() |
| .const_(constant_name) |
| .expr() |
| .path() |
| .ids(&[&*enum_canonical_name, referenced_name]) |
| .build() |
| .build(enum_rust_ty); |
| result.push(constant); |
| } |
| |
| let repr = self.repr() |
| .map(|repr| repr.to_rust_ty(ctx)) |
| .unwrap_or_else(|| helpers::ast_ty::raw_type(ctx, repr_name)); |
| |
| let mut builder = EnumBuilder::new(builder, |
| &name, |
| repr, |
| is_bitfield, |
| is_constified_enum); |
| |
| // A map where we keep a value -> variant relation. |
| let mut seen_values = HashMap::<_, String>::new(); |
| let enum_rust_ty = item.to_rust_ty(ctx); |
| let is_toplevel = item.is_toplevel(ctx); |
| |
| // Used to mangle the constants we generate in the unnamed-enum case. |
| let parent_canonical_name = if is_toplevel { |
| None |
| } else { |
| Some(item.parent_id().canonical_name(ctx)) |
| }; |
| |
| let constant_mangling_prefix = if enum_ty.name().is_none() { |
| parent_canonical_name.as_ref().map(|n| &*n) |
| } else { |
| Some(&name) |
| }; |
| |
| // NB: We defer the creation of constified variants, in case we find |
| // another variant with the same value (which is the common thing to |
| // do). |
| let mut constified_variants = VecDeque::new(); |
| |
| let mut iter = self.variants().iter().peekable(); |
| while let Some(variant) = iter.next() |
| .or_else(|| constified_variants.pop_front()) { |
| if variant.hidden() { |
| continue; |
| } |
| |
| if variant.force_constification() && iter.peek().is_some() { |
| constified_variants.push_back(variant); |
| continue; |
| } |
| |
| match seen_values.entry(variant.val()) { |
| Entry::Occupied(ref entry) => { |
| if is_rust_enum { |
| let variant_name = ctx.rust_mangle(variant.name()); |
| let mangled_name = if is_toplevel || |
| enum_ty.name().is_some() { |
| variant_name |
| } else { |
| let parent_name = parent_canonical_name.as_ref() |
| .unwrap(); |
| |
| Cow::Owned(format!("{}_{}", |
| parent_name, |
| variant_name)) |
| }; |
| |
| let existing_variant_name = entry.get(); |
| add_constant(enum_ty, |
| &name, |
| &*mangled_name, |
| existing_variant_name, |
| enum_rust_ty.clone(), |
| result); |
| } else { |
| builder = builder.with_variant(ctx, |
| variant, |
| constant_mangling_prefix, |
| enum_rust_ty.clone(), |
| result); |
| } |
| } |
| Entry::Vacant(entry) => { |
| builder = builder.with_variant(ctx, |
| variant, |
| constant_mangling_prefix, |
| enum_rust_ty.clone(), |
| result); |
| |
| let variant_name = ctx.rust_mangle(variant.name()); |
| |
| // If it's an unnamed enum, or constification is enforced, |
| // we also generate a constant so it can be properly |
| // accessed. |
| if (is_rust_enum && enum_ty.name().is_none()) || |
| variant.force_constification() { |
| let mangled_name = if is_toplevel { |
| variant_name.clone() |
| } else { |
| let parent_name = parent_canonical_name.as_ref() |
| .unwrap(); |
| |
| Cow::Owned(format!("{}_{}", |
| parent_name, |
| variant_name)) |
| }; |
| |
| add_constant(enum_ty, |
| &name, |
| &mangled_name, |
| &variant_name, |
| enum_rust_ty.clone(), |
| result); |
| } |
| |
| entry.insert(variant_name.into_owned()); |
| } |
| } |
| } |
| |
| let enum_ = builder.build(ctx, enum_rust_ty, result); |
| result.push(enum_); |
| } |
| } |
| |
| trait ToRustTy { |
| type Extra; |
| |
| fn to_rust_ty(&self, |
| ctx: &BindgenContext, |
| extra: &Self::Extra) |
| -> P<ast::Ty>; |
| } |
| |
| trait ItemToRustTy { |
| fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty>; |
| } |
| |
| // Convenience implementation. |
| impl ItemToRustTy for ItemId { |
| fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> { |
| ctx.resolve_item(*self).to_rust_ty(ctx) |
| } |
| } |
| |
| impl ItemToRustTy for Item { |
| fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> { |
| self.kind().expect_type().to_rust_ty(ctx, self) |
| } |
| } |
| |
| impl ToRustTy for Type { |
| type Extra = Item; |
| |
| fn to_rust_ty(&self, ctx: &BindgenContext, item: &Item) -> P<ast::Ty> { |
| use self::helpers::ast_ty::*; |
| |
| match *self.kind() { |
| TypeKind::Void => raw_type(ctx, "c_void"), |
| // TODO: we should do something smart with nullptr, or maybe *const |
| // c_void is enough? |
| TypeKind::NullPtr => { |
| raw_type(ctx, "c_void").to_ptr(true, ctx.span()) |
| } |
| TypeKind::Int(ik) => { |
| match ik { |
| IntKind::Bool => aster::ty::TyBuilder::new().bool(), |
| IntKind::Char => raw_type(ctx, "c_char"), |
| IntKind::UChar => raw_type(ctx, "c_uchar"), |
| IntKind::Short => raw_type(ctx, "c_short"), |
| IntKind::UShort => raw_type(ctx, "c_ushort"), |
| IntKind::Int => raw_type(ctx, "c_int"), |
| IntKind::UInt => raw_type(ctx, "c_uint"), |
| IntKind::Long => raw_type(ctx, "c_long"), |
| IntKind::ULong => raw_type(ctx, "c_ulong"), |
| IntKind::LongLong => raw_type(ctx, "c_longlong"), |
| IntKind::ULongLong => raw_type(ctx, "c_ulonglong"), |
| |
| IntKind::I8 => aster::ty::TyBuilder::new().i8(), |
| IntKind::U8 => aster::ty::TyBuilder::new().u8(), |
| IntKind::I16 => aster::ty::TyBuilder::new().i16(), |
| IntKind::U16 => aster::ty::TyBuilder::new().u16(), |
| IntKind::I32 => aster::ty::TyBuilder::new().i32(), |
| IntKind::U32 => aster::ty::TyBuilder::new().u32(), |
| IntKind::I64 => aster::ty::TyBuilder::new().i64(), |
| IntKind::U64 => aster::ty::TyBuilder::new().u64(), |
| IntKind::Custom { name, .. } => { |
| let ident = ctx.rust_ident_raw(name); |
| quote_ty!(ctx.ext_cx(), $ident) |
| } |
| // FIXME: This doesn't generate the proper alignment, but we |
| // can't do better right now. We should be able to use |
| // i128/u128 when they're available. |
| IntKind::U128 | IntKind::I128 => { |
| aster::ty::TyBuilder::new().array(2).u64() |
| } |
| } |
| } |
| TypeKind::Float(fk) => float_kind_rust_type(ctx, fk), |
| TypeKind::Complex(fk) => { |
| let float_path = float_kind_rust_type(ctx, fk); |
| |
| ctx.generated_bindegen_complex(); |
| if ctx.options().enable_cxx_namespaces { |
| quote_ty!(ctx.ext_cx(), root::__BindgenComplex<$float_path>) |
| } else { |
| quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>) |
| } |
| } |
| TypeKind::Function(ref fs) => { |
| let ty = fs.to_rust_ty(ctx, item); |
| let prefix = ctx.trait_prefix(); |
| quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>) |
| } |
| TypeKind::Array(item, len) => { |
| let inner = item.to_rust_ty(ctx); |
| aster::ty::TyBuilder::new().array(len).build(inner) |
| } |
| TypeKind::Enum(..) => { |
| let path = item.namespace_aware_canonical_path(ctx); |
| aster::AstBuilder::new().ty().path().ids(path).build() |
| } |
| TypeKind::TemplateInstantiation(inner, ref template_args) => { |
| // PS: Sorry for the duplication here. |
| let mut inner_ty = inner.to_rust_ty(ctx).unwrap(); |
| |
| if let ast::TyKind::Path(_, ref mut path) = inner_ty.node { |
| let template_args = template_args.iter() |
| .map(|arg| arg.to_rust_ty(ctx)) |
| .collect::<Vec<_>>(); |
| |
| path.segments.last_mut().unwrap().parameters = if |
| template_args.is_empty() { |
| None |
| } else { |
| Some(P(ast::PathParameters::AngleBracketed( |
| ast::AngleBracketedParameterData { |
| lifetimes: vec![], |
| types: P::from_vec(template_args), |
| bindings: P::from_vec(vec![]), |
| } |
| ))) |
| } |
| } |
| |
| P(inner_ty) |
| } |
| TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx), |
| TypeKind::TemplateAlias(inner, _) | |
| TypeKind::Alias(inner) => { |
| let applicable_named_args = item.applicable_template_args(ctx) |
| .into_iter() |
| .filter(|arg| ctx.resolve_type(*arg).is_named()) |
| .collect::<Vec<_>>(); |
| |
| let spelling = self.name().expect("Unnamed alias?"); |
| if item.is_opaque(ctx) && !applicable_named_args.is_empty() { |
| // Pray if there's no available layout. |
| let layout = self.layout(ctx).unwrap_or_else(Layout::zero); |
| BlobTyBuilder::new(layout).build() |
| } else if let Some(ty) = utils::type_from_named(ctx, |
| spelling, |
| inner) { |
| ty |
| } else { |
| utils::build_templated_path(item, |
| ctx, |
| applicable_named_args) |
| } |
| } |
| TypeKind::Comp(ref info) => { |
| let template_args = item.applicable_template_args(ctx); |
| if info.has_non_type_template_params() || |
| (item.is_opaque(ctx) && !template_args.is_empty()) { |
| return match self.layout(ctx) { |
| Some(layout) => BlobTyBuilder::new(layout).build(), |
| None => { |
| warn!("Couldn't compute layout for a type with non \ |
| type template params or opaque, expect \ |
| dragons!"); |
| aster::AstBuilder::new().ty().unit() |
| } |
| }; |
| } |
| |
| utils::build_templated_path(item, ctx, template_args) |
| } |
| TypeKind::BlockPointer => { |
| let void = raw_type(ctx, "c_void"); |
| void.to_ptr(/* is_const = */ |
| false, |
| ctx.span()) |
| } |
| TypeKind::Pointer(inner) | |
| TypeKind::Reference(inner) => { |
| let inner = ctx.resolve_item(inner); |
| let inner_ty = inner.expect_type(); |
| let ty = inner.to_rust_ty(ctx); |
| |
| // Avoid the first function pointer level, since it's already |
| // represented in Rust. |
| if inner_ty.canonical_type(ctx).is_function() { |
| ty |
| } else { |
| let is_const = self.is_const() || |
| inner.expect_type().is_const(); |
| ty.to_ptr(is_const, ctx.span()) |
| } |
| } |
| TypeKind::Named => { |
| let name = item.canonical_name(ctx); |
| let ident = ctx.rust_ident(&name); |
| quote_ty!(ctx.ext_cx(), $ident) |
| } |
| TypeKind::ObjCInterface(..) => quote_ty!(ctx.ext_cx(), id), |
| ref u @ TypeKind::UnresolvedTypeRef(..) => { |
| unreachable!("Should have been resolved after parsing {:?}!", u) |
| } |
| } |
| } |
| } |
| |
| impl ToRustTy for FunctionSig { |
| type Extra = Item; |
| |
| fn to_rust_ty(&self, ctx: &BindgenContext, _item: &Item) -> P<ast::Ty> { |
| // TODO: we might want to consider ignoring the reference return value. |
| let ret = utils::fnsig_return_ty(ctx, &self); |
| let arguments = utils::fnsig_arguments(ctx, &self); |
| |
| let decl = P(ast::FnDecl { |
| inputs: arguments, |
| output: ret, |
| variadic: self.is_variadic(), |
| }); |
| |
| let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { |
| unsafety: ast::Unsafety::Unsafe, |
| abi: self.abi().expect("Invalid abi for function!"), |
| lifetimes: vec![], |
| decl: decl, |
| })); |
| |
| P(ast::Ty { |
| id: ast::DUMMY_NODE_ID, |
| node: fnty, |
| span: ctx.span(), |
| }) |
| } |
| } |
| |
| impl CodeGenerator for Function { |
| type Extra = Item; |
| |
| fn codegen<'a>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'a>, |
| _whitelisted_items: &ItemSet, |
| item: &Item) { |
| debug!("<Function as CodeGenerator>::codegen: item = {:?}", item); |
| |
| let name = self.name(); |
| let mut canonical_name = item.canonical_name(ctx); |
| let mangled_name = self.mangled_name(); |
| |
| { |
| let seen_symbol_name = mangled_name.unwrap_or(&canonical_name); |
| |
| // TODO: Maybe warn here if there's a type/argument mismatch, or |
| // something? |
| if result.seen_function(seen_symbol_name) { |
| return; |
| } |
| result.saw_function(seen_symbol_name); |
| } |
| |
| let signature_item = ctx.resolve_item(self.signature()); |
| let signature = signature_item.kind().expect_type().canonical_type(ctx); |
| let signature = match *signature.kind() { |
| TypeKind::Function(ref sig) => sig, |
| _ => panic!("Signature kind is not a Function: {:?}", signature), |
| }; |
| |
| let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item); |
| |
| let mut attributes = vec![]; |
| |
| if ctx.options().generate_comments { |
| if let Some(comment) = item.comment() { |
| attributes.push(attributes::doc(comment)); |
| } |
| } |
| |
| if let Some(mangled) = mangled_name { |
| attributes.push(attributes::link_name(mangled)); |
| } else if name != canonical_name { |
| attributes.push(attributes::link_name(name)); |
| } |
| |
| let foreign_item_kind = |
| ast::ForeignItemKind::Fn(fndecl, ast::Generics::default()); |
| |
| // Handle overloaded functions by giving each overload its own unique |
| // suffix. |
| let times_seen = result.overload_number(&canonical_name); |
| if times_seen > 0 { |
| write!(&mut canonical_name, "{}", times_seen).unwrap(); |
| } |
| |
| let foreign_item = ast::ForeignItem { |
| ident: ctx.rust_ident_raw(&canonical_name), |
| attrs: attributes, |
| node: foreign_item_kind, |
| id: ast::DUMMY_NODE_ID, |
| span: ctx.span(), |
| vis: ast::Visibility::Public, |
| }; |
| |
| let item = ForeignModBuilder::new(signature.abi() |
| .expect("Invalid abi for function!")) |
| .with_foreign_item(foreign_item) |
| .build(ctx); |
| |
| result.push(item); |
| } |
| } |
| |
| impl CodeGenerator for ObjCInterface { |
| type Extra = Item; |
| fn codegen<'a>(&self, |
| ctx: &BindgenContext, |
| result: &mut CodegenResult<'a>, |
| _whitelisted_items: &ItemSet, |
| _: &Item) { |
| let mut impl_items = vec![]; |
| let mut trait_items = vec![]; |
| |
| for method in self.methods() { |
| let signature = method.signature(); |
| let fn_args = utils::fnsig_arguments(ctx, signature); |
| let fn_ret = utils::fnsig_return_ty(ctx, signature); |
| let sig = aster::AstBuilder::new() |
| .method_sig() |
| .unsafe_() |
| .fn_decl() |
| .self_() |
| .build(ast::SelfKind::Value(ast::Mutability::Immutable)) |
| .with_args(fn_args.clone()) |
| .build(fn_ret); |
| |
| // Collect the actual used argument names |
| let arg_names: Vec<_> = fn_args.iter() |
| .map(|ref arg| match arg.pat.node { |
| ast::PatKind::Ident(_, ref spanning, _) => { |
| spanning.node.name.as_str().to_string() |
| } |
| _ => { |
| panic!("odd argument!"); |
| } |
| }) |
| .collect(); |
| |
| let methods_and_args = |
| ctx.rust_ident(&method.format_method_call(&arg_names)); |
| let body = quote_stmt!(ctx.ext_cx(), |
| msg_send![self, $methods_and_args]) |
| .unwrap(); |
| let block = ast::Block { |
| stmts: vec![body], |
| id: ast::DUMMY_NODE_ID, |
| rules: ast::BlockCheckMode::Default, |
| span: ctx.span(), |
| }; |
| |
| let attrs = vec![]; |
| |
| let impl_item = ast::ImplItem { |
| id: ast::DUMMY_NODE_ID, |
| ident: ctx.rust_ident(method.rust_name()), |
| vis: ast::Visibility::Inherited, // Public, |
| attrs: attrs.clone(), |
| node: ast::ImplItemKind::Method(sig.clone(), P(block)), |
| defaultness: ast::Defaultness::Final, |
| span: ctx.span(), |
| }; |
| |
| let trait_item = ast::TraitItem { |
| id: ast::DUMMY_NODE_ID, |
| ident: ctx.rust_ident(method.rust_name()), |
| attrs: attrs, |
| node: ast::TraitItemKind::Method(sig, None), |
| span: ctx.span(), |
| }; |
| |
| impl_items.push(impl_item); |
| trait_items.push(trait_item) |
| } |
| |
| |
| let trait_block = aster::AstBuilder::new() |
| .item() |
| .pub_() |
| .trait_(self.name()) |
| .with_items(trait_items) |
| .build(); |
| |
| let ty_for_impl = quote_ty!(ctx.ext_cx(), id); |
| let impl_block = aster::AstBuilder::new() |
| .item() |
| .impl_() |
| .trait_() |
| .id(self.name()) |
| .build() |
| .with_items(impl_items) |
| .build_ty(ty_for_impl); |
| |
| result.push(trait_block); |
| result.push(impl_block); |
| result.saw_objc(); |
| } |
| } |
| |
| |
| |
| pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> { |
| context.gen(|context| { |
| let counter = Cell::new(0); |
| let mut result = CodegenResult::new(&counter); |
| |
| debug!("codegen: {:?}", context.options()); |
| |
| let whitelisted_items: ItemSet = context.whitelisted_items().collect(); |
| |
| if context.options().emit_ir { |
| for &id in whitelisted_items.iter() { |
| let item = context.resolve_item(id); |
| println!("ir: {:?} = {:#?}", id, item); |
| } |
| } |
| |
| if let Some(path) = context.options().emit_ir_graphviz.as_ref() { |
| match context.emit_ir_graphviz(path.clone()) { |
| Ok(()) => info!("Your dot file was generated successfully into: {}", path), |
| Err(e) => error!("{}", e), |
| } |
| } |
| |
| context.resolve_item(context.root_module()) |
| .codegen(context, &mut result, &whitelisted_items, &()); |
| |
| result.items |
| }) |
| } |
| |
| mod utils { |
| use super::ItemToRustTy; |
| use aster; |
| use ir::context::{BindgenContext, ItemId}; |
| use ir::function::FunctionSig; |
| use ir::item::{Item, ItemCanonicalPath}; |
| use ir::ty::TypeKind; |
| use std::mem; |
| use syntax::ast; |
| use syntax::ptr::P; |
| |
| pub fn prepend_objc_header(ctx: &BindgenContext, |
| result: &mut Vec<P<ast::Item>>) { |
| let use_objc = if ctx.options().objc_extern_crate { |
| quote_item!(ctx.ext_cx(), |
| use objc; |
| ) |
| .unwrap() |
| } else { |
| quote_item!(ctx.ext_cx(), |
| #[macro_use] |
| extern crate objc; |
| ) |
| .unwrap() |
| }; |
| |
| |
| let id_type = quote_item!(ctx.ext_cx(), |
| #[allow(non_camel_case_types)] |
| pub type id = *mut objc::runtime::Object; |
| ) |
| .unwrap(); |
| |
| let items = vec![use_objc, id_type]; |
| let old_items = mem::replace(result, items); |
| result.extend(old_items.into_iter()); |
| } |
| |
| pub fn prepend_union_types(ctx: &BindgenContext, |
| result: &mut Vec<P<ast::Item>>) { |
| let prefix = ctx.trait_prefix(); |
| |
| // TODO(emilio): The fmt::Debug impl could be way nicer with |
| // std::intrinsics::type_name, but... |
| let union_field_decl = quote_item!(ctx.ext_cx(), |
| #[repr(C)] |
| pub struct __BindgenUnionField<T>( |
| ::$prefix::marker::PhantomData<T>); |
| ) |
| .unwrap(); |
| |
| let union_field_impl = quote_item!(&ctx.ext_cx(), |
| impl<T> __BindgenUnionField<T> { |
| #[inline] |
| pub fn new() -> Self { |
| __BindgenUnionField(::$prefix::marker::PhantomData) |
| } |
| |
| #[inline] |
| pub unsafe fn as_ref(&self) -> &T { |
| ::$prefix::mem::transmute(self) |
| } |
| |
| #[inline] |
| pub unsafe fn as_mut(&mut self) -> &mut T { |
| ::$prefix::mem::transmute(self) |
| } |
| } |
| ) |
| .unwrap(); |
| |
| let union_field_default_impl = quote_item!(&ctx.ext_cx(), |
| impl<T> ::$prefix::default::Default for __BindgenUnionField<T> { |
| #[inline] |
| fn default() -> Self { |
| Self::new() |
| } |
| } |
| ) |
| .unwrap(); |
| |
| let union_field_clone_impl = quote_item!(&ctx.ext_cx(), |
| impl<T> ::$prefix::clone::Clone for __BindgenUnionField<T> { |
| #[inline] |
| fn clone(&self) -> Self { |
| Self::new() |
| } |
| } |
| ) |
| .unwrap(); |
| |
| let union_field_copy_impl = quote_item!(&ctx.ext_cx(), |
| impl<T> ::$prefix::marker::Copy for __BindgenUnionField<T> {} |
| ) |
| .unwrap(); |
| |
| let union_field_debug_impl = quote_item!(ctx.ext_cx(), |
| impl<T> ::$prefix::fmt::Debug for __BindgenUnionField<T> { |
| fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) |
| -> ::$prefix::fmt::Result { |
| fmt.write_str("__BindgenUnionField") |
| } |
| } |
| ) |
| .unwrap(); |
| |
| let items = vec![union_field_decl, |
| union_field_impl, |
| union_field_default_impl, |
| union_field_clone_impl, |
| union_field_copy_impl, |
| union_field_debug_impl]; |
| |
| let old_items = mem::replace(result, items); |
| result.extend(old_items.into_iter()); |
| } |
| |
| pub fn prepend_incomplete_array_types(ctx: &BindgenContext, |
| result: &mut Vec<P<ast::Item>>) { |
| let prefix = ctx.trait_prefix(); |
| |
| let incomplete_array_decl = quote_item!(ctx.ext_cx(), |
| #[repr(C)] |
| #[derive(Default)] |
| pub struct __IncompleteArrayField<T>( |
| ::$prefix::marker::PhantomData<T>); |
| ) |
| .unwrap(); |
| |
| let incomplete_array_impl = quote_item!(&ctx.ext_cx(), |
| impl<T> __IncompleteArrayField<T> { |
| #[inline] |
| pub fn new() -> Self { |
| __IncompleteArrayField(::$prefix::marker::PhantomData) |
| } |
| |
| #[inline] |
| pub unsafe fn as_ptr(&self) -> *const T { |
| ::$prefix::mem::transmute(self) |
| } |
| |
| #[inline] |
| pub unsafe fn as_mut_ptr(&mut self) -> *mut T { |
| ::$prefix::mem::transmute(self) |
| } |
| |
| #[inline] |
| pub unsafe fn as_slice(&self, len: usize) -> &[T] { |
| ::$prefix::slice::from_raw_parts(self.as_ptr(), len) |
| } |
| |
| #[inline] |
| pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { |
| ::$prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) |
| } |
| } |
| ) |
| .unwrap(); |
| |
| let incomplete_array_debug_impl = quote_item!(ctx.ext_cx(), |
| impl<T> ::$prefix::fmt::Debug for __IncompleteArrayField<T> { |
| fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) |
| -> ::$prefix::fmt::Result { |
| fmt.write_str("__IncompleteArrayField") |
| } |
| } |
| ) |
| .unwrap(); |
| |
| let incomplete_array_clone_impl = quote_item!(&ctx.ext_cx(), |
| impl<T> ::$prefix::clone::Clone for __IncompleteArrayField<T> { |
| #[inline] |
| fn clone(&self) -> Self { |
| Self::new() |
| } |
| } |
| ) |
| .unwrap(); |
| |
| let incomplete_array_copy_impl = quote_item!(&ctx.ext_cx(), |
| impl<T> ::$prefix::marker::Copy for __IncompleteArrayField<T> {} |
| ) |
| .unwrap(); |
| |
| let items = vec![incomplete_array_decl, |
| incomplete_array_impl, |
| incomplete_array_debug_impl, |
| incomplete_array_clone_impl, |
| incomplete_array_copy_impl]; |
| |
| let old_items = mem::replace(result, items); |
| result.extend(old_items.into_iter()); |
| } |
| |
| pub fn prepend_complex_type(ctx: &BindgenContext, |
| result: &mut Vec<P<ast::Item>>) { |
| let complex_type = quote_item!(ctx.ext_cx(), |
| #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] |
| #[repr(C)] |
| pub struct __BindgenComplex<T> { |
| pub re: T, |
| pub im: T |
| } |
| ) |
| .unwrap(); |
| |
| let items = vec![complex_type]; |
| let old_items = mem::replace(result, items); |
| result.extend(old_items.into_iter()); |
| } |
| |
| pub fn build_templated_path(item: &Item, |
| ctx: &BindgenContext, |
| template_args: Vec<ItemId>) |
| -> P<ast::Ty> { |
| let path = item.namespace_aware_canonical_path(ctx); |
| let builder = aster::AstBuilder::new().ty().path(); |
| |
| let template_args = template_args.iter() |
| .map(|arg| arg.to_rust_ty(ctx)) |
| .collect::<Vec<_>>(); |
| |
| // XXX: I suck at aster. |
| if path.len() == 1 { |
| return builder.segment(&path[0]) |
| .with_tys(template_args) |
| .build() |
| .build(); |
| } |
| |
| let mut builder = builder.id(&path[0]); |
| for (i, segment) in path.iter().skip(1).enumerate() { |
| // Take into account the skip(1) |
| builder = if i == path.len() - 2 { |
| // XXX Extra clone courtesy of the borrow checker. |
| builder.segment(&segment) |
| .with_tys(template_args.clone()) |
| .build() |
| } else { |
| builder.segment(&segment).build() |
| } |
| } |
| |
| builder.build() |
| } |
| |
| fn primitive_ty(ctx: &BindgenContext, name: &str) -> P<ast::Ty> { |
| let ident = ctx.rust_ident_raw(&name); |
| quote_ty!(ctx.ext_cx(), $ident) |
| } |
| |
| pub fn type_from_named(ctx: &BindgenContext, |
| name: &str, |
| _inner: ItemId) |
| -> Option<P<ast::Ty>> { |
| // FIXME: We could use the inner item to check this is really a |
| // primitive type but, who the heck overrides these anyway? |
| Some(match name { |
| "int8_t" => primitive_ty(ctx, "i8"), |
| "uint8_t" => primitive_ty(ctx, "u8"), |
| "int16_t" => primitive_ty(ctx, "i16"), |
| "uint16_t" => primitive_ty(ctx, "u16"), |
| "int32_t" => primitive_ty(ctx, "i32"), |
| "uint32_t" => primitive_ty(ctx, "u32"), |
| "int64_t" => primitive_ty(ctx, "i64"), |
| "uint64_t" => primitive_ty(ctx, "u64"), |
| |
| "uintptr_t" | "size_t" => primitive_ty(ctx, "usize"), |
| |
| "intptr_t" | "ptrdiff_t" | "ssize_t" => primitive_ty(ctx, "isize"), |
| _ => return None, |
| }) |
| } |
| |
| pub fn rust_fndecl_from_signature(ctx: &BindgenContext, |
| sig: &Item) |
| -> P<ast::FnDecl> { |
| use codegen::ToRustTy; |
| |
| let signature = sig.kind().expect_type().canonical_type(ctx); |
| let signature = match *signature.kind() { |
| TypeKind::Function(ref sig) => sig, |
| _ => panic!("How?"), |
| }; |
| |
| let decl_ty = signature.to_rust_ty(ctx, sig); |
| match decl_ty.unwrap().node { |
| ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl, |
| _ => panic!("How did this happen exactly?"), |
| } |
| } |
| |
| pub fn fnsig_return_ty(ctx: &BindgenContext, |
| sig: &FunctionSig) |
| -> ast::FunctionRetTy { |
| let return_item = ctx.resolve_item(sig.return_type()); |
| if let TypeKind::Void = *return_item.kind().expect_type().kind() { |
| ast::FunctionRetTy::Default(ctx.span()) |
| } else { |
| ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx)) |
| } |
| } |
| |
| pub fn fnsig_arguments(ctx: &BindgenContext, |
| sig: &FunctionSig) |
| -> Vec<ast::Arg> { |
| use super::ToPtr; |
| let mut unnamed_arguments = 0; |
| sig.argument_types().iter().map(|&(ref name, ty)| { |
| let arg_item = ctx.resolve_item(ty); |
| let arg_ty = arg_item.kind().expect_type(); |
| |
| // From the C90 standard[1]: |
| // |
| // A declaration of a parameter as "array of type" shall be |
| // adjusted to "qualified pointer to type", where the type |
| // qualifiers (if any) are those specified within the [ and ] of |
| // the array type derivation. |
| // |
| // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html |
| let arg_ty = match *arg_ty.canonical_type(ctx).kind() { |
| TypeKind::Array(t, _) => { |
| t.to_rust_ty(ctx).to_ptr(ctx.resolve_type(t).is_const(), ctx.span()) |
| }, |
| TypeKind::Pointer(inner) => { |
| let inner = ctx.resolve_item(inner); |
| let inner_ty = inner.expect_type(); |
| if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() { |
| quote_ty!(ctx.ext_cx(), id) |
| } else { |
| arg_item.to_rust_ty(ctx) |
| } |
| }, |
| _ => { |
| arg_item.to_rust_ty(ctx) |
| } |
| }; |
| |
| let arg_name = match *name { |
| Some(ref name) => ctx.rust_mangle(name).into_owned(), |
| None => { |
| unnamed_arguments += 1; |
| format!("arg{}", unnamed_arguments) |
| } |
| }; |
| |
| assert!(!arg_name.is_empty()); |
| |
| ast::Arg { |
| ty: arg_ty, |
| pat: aster::AstBuilder::new().pat().id(arg_name), |
| id: ast::DUMMY_NODE_ID, |
| } |
| }).collect::<Vec<_>>() |
| } |
| } |