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 { 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 { 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>, /// 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, /// 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, /// 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, vars_seen: HashSet, /// 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, } impl<'a> CodegenResult<'a> { fn new(codegen_id: &'a Cell) -> 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(&mut self, cb: F) -> Vec> 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>; 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(mut self, items: I) -> Self where I: IntoIterator, { self.inner.items.extend(items.into_iter()); self } fn build(self, ctx: &BindgenContext) -> P { 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; } impl ToPtr for P { 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!("::codegen: Ignoring hidden or seen: \ self = {:?}", self); return; } debug!("::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!("::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!("::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!("::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 { 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, methods: &mut Vec) -> 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!("::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 = 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::>>(); 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, method_names: &mut HashMap, result: &mut CodegenResult<'a>, whitelisted_items: &ItemSet, parent: &CompInfo); } impl MethodCodegen for Method { fn codegen_method<'a>(&self, ctx: &BindgenContext, methods: &mut Vec, method_names: &mut HashMap, 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), Bitfield { canonical_name: &'a str, aster: P, }, Consts { aster: P }, } 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, name: &'a str, repr: P, 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, 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, result: &mut CodegenResult<'b>) -> P { 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!("::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, 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; } trait ItemToRustTy { fn to_rust_ty(&self, ctx: &BindgenContext) -> P; } // Convenience implementation. impl ItemToRustTy for ItemId { fn to_rust_ty(&self, ctx: &BindgenContext) -> P { ctx.resolve_item(*self).to_rust_ty(ctx) } } impl ItemToRustTy for Item { fn to_rust_ty(&self, ctx: &BindgenContext) -> P { 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 { 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::>(); 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::>(); 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 { // 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!("::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> { 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>) { 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>) { 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( ::$prefix::marker::PhantomData); ) .unwrap(); let union_field_impl = quote_item!(&ctx.ext_cx(), impl __BindgenUnionField { #[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 ::$prefix::default::Default for __BindgenUnionField { #[inline] fn default() -> Self { Self::new() } } ) .unwrap(); let union_field_clone_impl = quote_item!(&ctx.ext_cx(), impl ::$prefix::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } ) .unwrap(); let union_field_copy_impl = quote_item!(&ctx.ext_cx(), impl ::$prefix::marker::Copy for __BindgenUnionField {} ) .unwrap(); let union_field_debug_impl = quote_item!(ctx.ext_cx(), impl ::$prefix::fmt::Debug for __BindgenUnionField { 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>) { let prefix = ctx.trait_prefix(); let incomplete_array_decl = quote_item!(ctx.ext_cx(), #[repr(C)] #[derive(Default)] pub struct __IncompleteArrayField( ::$prefix::marker::PhantomData); ) .unwrap(); let incomplete_array_impl = quote_item!(&ctx.ext_cx(), impl __IncompleteArrayField { #[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 ::$prefix::fmt::Debug for __IncompleteArrayField { 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 ::$prefix::clone::Clone for __IncompleteArrayField { #[inline] fn clone(&self) -> Self { Self::new() } } ) .unwrap(); let incomplete_array_copy_impl = quote_item!(&ctx.ext_cx(), impl ::$prefix::marker::Copy for __IncompleteArrayField {} ) .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>) { let complex_type = quote_item!(ctx.ext_cx(), #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[repr(C)] pub struct __BindgenComplex { 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) -> P { 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::>(); // 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 { 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> { // 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 { 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 { 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::>() } }