mod dyngen; pub(crate) mod error; mod helpers; mod impl_debug; mod impl_partialeq; mod postprocessing; mod serialize; pub(crate) mod struct_layout; #[cfg(test)] #[allow(warnings)] pub(crate) mod bitfield_unit; #[cfg(all(test, target_endian = "little"))] mod bitfield_unit_tests; use self::dyngen::DynamicItems; use self::helpers::attributes; use self::struct_layout::StructLayoutTracker; use super::BindgenOptions; use crate::callbacks::{DeriveInfo, FieldInfo, TypeKind as DeriveTypeKind}; use crate::codegen::error::Error; use crate::ir::analysis::{HasVtable, Sizedness}; use crate::ir::annotations::{ Annotations, FieldAccessorKind, FieldVisibilityKind, }; use crate::ir::comp::{ Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData, FieldMethods, Method, MethodKind, }; use crate::ir::context::{BindgenContext, ItemId}; use crate::ir::derive::{ CanDerive, CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq, CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd, }; use crate::ir::dot; use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; use crate::ir::function::{ ClangAbi, Function, FunctionKind, FunctionSig, Linkage, }; use crate::ir::int::IntKind; use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath}; use crate::ir::item_kind::ItemKind; use crate::ir::layout::Layout; use crate::ir::module::Module; use crate::ir::objc::{ObjCInterface, ObjCMethod}; use crate::ir::template::{ AsTemplateParam, TemplateInstantiation, TemplateParameters, }; use crate::ir::ty::{Type, TypeKind}; use crate::ir::var::Var; use proc_macro2::{self, Ident, Span}; use quote::TokenStreamExt; use crate::{Entry, HashMap, HashSet}; use std::borrow::Cow; use std::cell::Cell; use std::collections::VecDeque; use std::ffi::CStr; use std::fmt::{self, Write}; use std::ops; use std::str::{self, FromStr}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum CodegenError { Serialize { msg: String, loc: String }, Io(String), } impl From for CodegenError { fn from(err: std::io::Error) -> Self { Self::Io(err.to_string()) } } impl fmt::Display for CodegenError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Serialize { msg, loc } => { write!(f, "serialization error at {}: {}", loc, msg) } Self::Io(err) => err.fmt(f), } } } // Name of type defined in constified enum module pub(crate) static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type"; fn top_level_path( ctx: &BindgenContext, item: &Item, ) -> Vec { let mut path = vec![quote! { self }]; if ctx.options().enable_cxx_namespaces { for _ in 0..item.codegen_depth(ctx) { path.push(quote! { super }); } } path } fn root_import( ctx: &BindgenContext, module: &Item, ) -> proc_macro2::TokenStream { 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(quote! { #root_ident }); let mut tokens = quote! {}; tokens.append_separated(path, quote!(::)); quote! { #[allow(unused_imports)] use #tokens ; } } bitflags! { #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] struct DerivableTraits: u16 { const DEBUG = 1 << 0; const DEFAULT = 1 << 1; const COPY = 1 << 2; const CLONE = 1 << 3; const HASH = 1 << 4; const PARTIAL_ORD = 1 << 5; const ORD = 1 << 6; const PARTIAL_EQ = 1 << 7; const EQ = 1 << 8; } } fn derives_of_item( item: &Item, ctx: &BindgenContext, packed: bool, ) -> DerivableTraits { let mut derivable_traits = DerivableTraits::empty(); let all_template_params = item.all_template_params(ctx); if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() { derivable_traits |= DerivableTraits::COPY; if ctx.options().rust_features().builtin_clone_impls || !all_template_params.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. derivable_traits |= DerivableTraits::CLONE; } } else if packed { // If the struct or union is packed, deriving from Copy is required for // deriving from any other trait. return derivable_traits; } if item.can_derive_debug(ctx) && !item.annotations().disallow_debug() { derivable_traits |= DerivableTraits::DEBUG; } if item.can_derive_default(ctx) && !item.annotations().disallow_default() { derivable_traits |= DerivableTraits::DEFAULT; } if item.can_derive_hash(ctx) { derivable_traits |= DerivableTraits::HASH; } if item.can_derive_partialord(ctx) { derivable_traits |= DerivableTraits::PARTIAL_ORD; } if item.can_derive_ord(ctx) { derivable_traits |= DerivableTraits::ORD; } if item.can_derive_partialeq(ctx) { derivable_traits |= DerivableTraits::PARTIAL_EQ; } if item.can_derive_eq(ctx) { derivable_traits |= DerivableTraits::EQ; } derivable_traits } impl From for Vec<&'static str> { fn from(derivable_traits: DerivableTraits) -> Vec<&'static str> { [ (DerivableTraits::DEBUG, "Debug"), (DerivableTraits::DEFAULT, "Default"), (DerivableTraits::COPY, "Copy"), (DerivableTraits::CLONE, "Clone"), (DerivableTraits::HASH, "Hash"), (DerivableTraits::PARTIAL_ORD, "PartialOrd"), (DerivableTraits::ORD, "Ord"), (DerivableTraits::PARTIAL_EQ, "PartialEq"), (DerivableTraits::EQ, "Eq"), ] .iter() .filter_map(|&(flag, derive)| { Some(derive).filter(|_| derivable_traits.contains(flag)) }) .collect() } } struct WrapAsVariadic { new_name: String, idx_of_va_list_arg: usize, } struct CodegenResult<'a> { items: Vec, dynamic_items: DynamicItems, /// 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 a bindgen union has been generated at least once. saw_bindgen_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, /// Whether Apple block types have been seen at least once. saw_block: bool, /// Whether a bitfield allocation unit has been seen at least once. saw_bitfield_unit: 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, /// List of items to serialize. With optionally the argument for the wrap as /// variadic transformation to be applied. items_to_serialize: Vec<(ItemId, Option)>, } impl<'a> CodegenResult<'a> { fn new(codegen_id: &'a Cell) -> Self { CodegenResult { items: vec![], dynamic_items: DynamicItems::new(), saw_bindgen_union: false, saw_incomplete_array: false, saw_objc: false, saw_block: false, saw_bitfield_unit: false, codegen_id, items_seen: Default::default(), functions_seen: Default::default(), vars_seen: Default::default(), overload_counters: Default::default(), items_to_serialize: Default::default(), } } fn dynamic_items(&mut self) -> &mut DynamicItems { &mut self.dynamic_items } fn saw_bindgen_union(&mut self) { self.saw_bindgen_union = true; } fn saw_incomplete_array(&mut self) { self.saw_incomplete_array = true; } fn saw_objc(&mut self) { self.saw_objc = true; } fn saw_block(&mut self) { self.saw_block = true; } fn saw_bitfield_unit(&mut self) { self.saw_bitfield_unit = true; } fn seen>(&self, item: Id) -> bool { self.items_seen.contains(&item.into()) } fn set_seen>(&mut self, item: Id) { self.items_seen.insert(item.into()); } 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 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_incomplete_array |= new.saw_incomplete_array; self.saw_objc |= new.saw_objc; self.saw_block |= new.saw_block; self.saw_bitfield_unit |= new.saw_bitfield_unit; self.saw_bindgen_union |= new.saw_bindgen_union; 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 } } /// A trait to convert a rust type into a pointer, optionally const, to the same /// type. trait ToPtr { fn to_ptr(self, is_const: bool) -> syn::Type; } impl ToPtr for syn::Type { fn to_ptr(self, is_const: bool) -> syn::Type { if is_const { syn::parse_quote! { *const #self } } else { syn::parse_quote! { *mut #self } } } } /// An extension trait for `syn::Type` that lets us append any implicit /// template parameters that exist for some type, if necessary. trait WithImplicitTemplateParams { fn with_implicit_template_params( self, ctx: &BindgenContext, item: &Item, ) -> Self; } impl WithImplicitTemplateParams for syn::Type { fn with_implicit_template_params( self, ctx: &BindgenContext, item: &Item, ) -> Self { let item = item.id().into_resolver().through_type_refs().resolve(ctx); let params = match *item.expect_type().kind() { TypeKind::UnresolvedTypeRef(..) => { unreachable!("already resolved unresolved type refs") } TypeKind::ResolvedTypeRef(..) => { unreachable!("we resolved item through type refs") } // None of these types ever have implicit template parameters. TypeKind::Void | TypeKind::NullPtr | TypeKind::Pointer(..) | TypeKind::Reference(..) | TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::Complex(..) | TypeKind::Array(..) | TypeKind::TypeParam | TypeKind::Opaque | TypeKind::Function(..) | TypeKind::Enum(..) | TypeKind::ObjCId | TypeKind::ObjCSel | TypeKind::TemplateInstantiation(..) => None, _ => { let params = item.used_template_params(ctx); if params.is_empty() { None } else { Some(params.into_iter().map(|p| { p.try_to_rust_ty(ctx, &()).expect( "template params cannot fail to be a rust type", ) })) } } }; if let Some(params) = params { syn::parse_quote! { #self<#(#params),*> } } else { self } } } trait CodeGenerator { /// Extra information from the caller. type Extra; /// Extra information returned to the caller. type Return; fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, extra: &Self::Extra, ) -> Self::Return; } impl Item { fn process_before_codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult, ) -> bool { if !self.is_enabled_for_codegen(ctx) { return false; } if self.is_blocklisted(ctx) || result.seen(self.id()) { debug!( "::process_before_codegen: Ignoring hidden or seen: \ self = {:?}", self ); return false; } if !ctx.codegen_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. warn!("Found non-allowlisted item in code generation: {:?}", self); } result.set_seen(self.id()); true } } impl CodeGenerator for Item { type Extra = (); type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, _extra: &(), ) { debug!("::codegen: self = {:?}", self); if !self.process_before_codegen(ctx, result) { return; } match *self.kind() { ItemKind::Module(ref module) => { module.codegen(ctx, result, self); } ItemKind::Function(ref fun) => { fun.codegen(ctx, result, self); } ItemKind::Var(ref var) => { var.codegen(ctx, result, self); } ItemKind::Type(ref ty) => { ty.codegen(ctx, result, self); } } } } impl CodeGenerator for Module { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug!("::codegen: item = {:?}", item); let codegen_self = |result: &mut CodegenResult, found_any: &mut bool| { for child in self.children() { if ctx.codegen_items().contains(child) { *found_any = true; ctx.resolve_item(*child).codegen(ctx, result, &()); } } if item.id() == ctx.root_module() { if result.saw_block { utils::prepend_block_header(ctx, &mut *result); } if result.saw_bindgen_union { utils::prepend_union_types(ctx, &mut *result); } if result.saw_incomplete_array { utils::prepend_incomplete_array_types(ctx, &mut *result); } if ctx.need_bindgen_float16_type() { utils::prepend_float16_type(&mut *result); } if ctx.need_bindgen_complex_type() { utils::prepend_complex_type(&mut *result); } if result.saw_objc { utils::prepend_objc_header(ctx, &mut *result); } if result.saw_bitfield_unit { utils::prepend_bitfield_unit_type(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)); let path = item .namespace_aware_canonical_path(ctx) .join("::") .into_boxed_str(); if let Some(raw_lines) = ctx.options().module_lines.get(&path) { for raw_line in raw_lines { found_any = true; result.push( proc_macro2::TokenStream::from_str(raw_line).unwrap(), ); } } codegen_self(result, &mut found_any); }); // Don't bother creating an empty module. if !found_any { return; } let name = item.canonical_name(ctx); let ident = ctx.rust_ident(name); result.push(if item.id() == ctx.root_module() { quote! { #[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] pub mod #ident { #( #inner_items )* } } } else { quote! { pub mod #ident { #( #inner_items )* } } }); } } impl CodeGenerator for Var { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { use crate::ir::var::VarType; debug!("::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); let canonical_name = item.canonical_name(ctx); if result.seen_var(&canonical_name) { return; } result.saw_var(&canonical_name); let canonical_ident = ctx.rust_ident(&canonical_name); // We can't generate bindings to static variables of templates. The // number of actual variables for a single declaration are open ended // and we don't know what instantiations do or don't exist. if !item.all_template_params(ctx).is_empty() { return; } let mut attrs = vec![]; if let Some(comment) = item.comment(ctx) { attrs.push(attributes::doc(comment)); } let var_ty = self.ty(); let ty = var_ty.to_rust_ty_or_opaque(ctx, &()); if let Some(val) = self.val() { match *val { VarType::Bool(val) => { result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #val ; }); } VarType::Int(val) => { let int_kind = var_ty .into_resolver() .through_type_aliases() .through_type_refs() .resolve(ctx) .expect_type() .as_integer() .unwrap(); let val = if int_kind.is_signed() { helpers::ast_ty::int_expr(val) } else { helpers::ast_ty::uint_expr(val as _) }; result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #val ; }); } VarType::String(ref bytes) => { let prefix = ctx.trait_prefix(); let options = ctx.options(); let rust_features = options.rust_features; let mut cstr_bytes = bytes.clone(); cstr_bytes.push(0); let len = proc_macro2::Literal::usize_unsuffixed( cstr_bytes.len(), ); // TODO: Here we ignore the type we just made up, probably // we should refactor how the variable type and ty ID work. let array_ty = quote! { [u8; #len] }; let cstr_ty = quote! { ::#prefix::ffi::CStr }; let bytes = proc_macro2::Literal::byte_string(&cstr_bytes); if options.generate_cstr && rust_features.const_cstr && CStr::from_bytes_with_nul(&cstr_bytes).is_ok() { result.push(quote! { #(#attrs)* #[allow(unsafe_code)] pub const #canonical_ident: &#cstr_ty = unsafe { #cstr_ty::from_bytes_with_nul_unchecked(#bytes) }; }); } else { let lifetime = if rust_features.static_lifetime_elision { None } else { Some(quote! { 'static }) } .into_iter(); result.push(quote! { #(#attrs)* pub const #canonical_ident: &#(#lifetime )*#array_ty = #bytes ; }); } } VarType::Float(f) => { if let Ok(expr) = helpers::ast_ty::float_expr(ctx, f) { result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #expr ; }); } } VarType::Char(c) => { result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #c ; }); } } } else { // If necessary, apply a `#[link_name]` attribute if let Some(link_name) = self.link_name() { attrs.push(attributes::link_name::(link_name)); } else { let link_name = self.mangled_name().unwrap_or_else(|| self.name()); if !utils::names_will_be_identical_after_mangling( &canonical_name, link_name, None, ) { attrs.push(attributes::link_name::(link_name)); } } let maybe_mut = if self.is_const() { quote! {} } else { quote! { mut } }; let tokens = quote!( extern "C" { #(#attrs)* pub static #maybe_mut #canonical_ident: #ty; } ); result.push(tokens); } } } impl CodeGenerator for Type { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug!("::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); match *self.kind() { TypeKind::Void | TypeKind::NullPtr | TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::Complex(..) | TypeKind::Array(..) | TypeKind::Vector(..) | TypeKind::Pointer(..) | TypeKind::Reference(..) | TypeKind::Function(..) | TypeKind::ResolvedTypeRef(..) | TypeKind::Opaque | TypeKind::TypeParam => { // These items don't need code generation, they only need to be // converted to rust types in fields, arguments, and such. // NOTE(emilio): If you add to this list, make sure to also add // it to BindgenContext::compute_allowlisted_and_codegen_items. } TypeKind::TemplateInstantiation(ref inst) => { inst.codegen(ctx, result, item) } TypeKind::BlockPointer(inner) => { if !ctx.options().generate_block { return; } let inner_item = inner.into_resolver().through_type_refs().resolve(ctx); let name = item.canonical_name(ctx); let inner_rust_type = { if let TypeKind::Function(fnsig) = inner_item.kind().expect_type().kind() { utils::fnsig_block(ctx, fnsig) } else { panic!("invalid block typedef: {:?}", inner_item) } }; let rust_name = ctx.rust_ident(name); let mut tokens = if let Some(comment) = item.comment(ctx) { attributes::doc(comment) } else { quote! {} }; tokens.append_all(quote! { pub type #rust_name = #inner_rust_type ; }); result.push(tokens); result.saw_block(); } TypeKind::Comp(ref ci) => ci.codegen(ctx, result, item), TypeKind::TemplateAlias(inner, _) | TypeKind::Alias(inner) => { let inner_item = inner.into_resolver().through_type_refs().resolve(ctx); let name = item.canonical_name(ctx); let path = item.canonical_path(ctx); { let through_type_aliases = inner .into_resolver() .through_type_refs() .through_type_aliases() .resolve(ctx); // Try to catch the common pattern: // // typedef struct foo { ... } foo; // // here, and also other more complex cases like #946. if through_type_aliases.canonical_path(ctx) == path { return; } } // If this is a known named type, disallow generating anything // for it too. If size_t -> usize conversions are enabled, we // need to check that these conversions are permissible, but // nothing needs to be generated, still. let spelling = self.name().expect("Unnamed alias?"); if utils::type_from_named(ctx, spelling).is_some() { if let "size_t" | "ssize_t" = spelling { let layout = inner_item .kind() .expect_type() .layout(ctx) .expect("No layout?"); assert_eq!( layout.size, ctx.target_pointer_size(), "Target platform requires `--no-size_t-is-usize`. The size of `{}` ({}) does not match the target pointer size ({})", spelling, layout.size, ctx.target_pointer_size(), ); assert_eq!( layout.align, ctx.target_pointer_size(), "Target platform requires `--no-size_t-is-usize`. The alignment of `{}` ({}) does not match the target pointer size ({})", spelling, layout.align, ctx.target_pointer_size(), ); } return; } let mut outer_params = item.used_template_params(ctx); let is_opaque = item.is_opaque(ctx, &()); let inner_rust_type = if is_opaque { outer_params = vec![]; self.to_opaque(ctx, item) } else { // Its possible that we have better layout information than // the inner type does, so fall back to an opaque blob based // on our layout if converting the inner item fails. inner_item .try_to_rust_ty_or_opaque(ctx, &()) .unwrap_or_else(|_| self.to_opaque(ctx, item)) .with_implicit_template_params(ctx, inner_item) }; { // 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_type_param() { warn!( "Item contained invalid named type, skipping: \ {:?}, {:?}", item, inner_item ); return; } } let rust_name = ctx.rust_ident(&name); let mut tokens = if let Some(comment) = item.comment(ctx) { attributes::doc(comment) } else { quote! {} }; let alias_style = if ctx.options().type_alias.matches(&name) { AliasVariation::TypeAlias } else if ctx.options().new_type_alias.matches(&name) { AliasVariation::NewType } else if ctx.options().new_type_alias_deref.matches(&name) { AliasVariation::NewTypeDeref } else { ctx.options().default_alias_style }; // We prefer using `pub use` over `pub type` because of: // https://github.com/rust-lang/rust/issues/26264 if matches!(inner_rust_type, syn::Type::Path(_)) && outer_params.is_empty() && !is_opaque && alias_style == AliasVariation::TypeAlias && inner_item.expect_type().canonical_type(ctx).is_enum() { tokens.append_all(quote! { pub use }); let path = top_level_path(ctx, item); tokens.append_separated(path, quote!(::)); tokens.append_all(quote! { :: #inner_rust_type as #rust_name ; }); result.push(tokens); return; } tokens.append_all(match alias_style { AliasVariation::TypeAlias => quote! { pub type #rust_name }, AliasVariation::NewType | AliasVariation::NewTypeDeref => { assert!( ctx.options().rust_features().repr_transparent, "repr_transparent feature is required to use {:?}", alias_style ); let mut attributes = vec![attributes::repr("transparent")]; let packed = false; // Types can't be packed in Rust. let derivable_traits = derives_of_item(item, ctx, packed); if !derivable_traits.is_empty() { let derives: Vec<_> = derivable_traits.into(); attributes.push(attributes::derives(&derives)) } quote! { #( #attributes )* pub struct #rust_name } } }); let params: Vec<_> = outer_params .into_iter() .filter_map(|p| p.as_template_param(ctx, &())) .collect(); if params .iter() .any(|p| ctx.resolve_type(*p).is_invalid_type_param()) { warn!( "Item contained invalid template \ parameter: {:?}", item ); return; } let params: Vec<_> = params .iter() .map(|p| { p.try_to_rust_ty(ctx, &()).expect( "type parameters can always convert to rust ty OK", ) }) .collect(); if !params.is_empty() { tokens.append_all(quote! { < #( #params ),* > }); } let access_spec = access_specifier(ctx.options().default_visibility); tokens.append_all(match alias_style { AliasVariation::TypeAlias => quote! { = #inner_rust_type ; }, AliasVariation::NewType | AliasVariation::NewTypeDeref => { quote! { (#access_spec #inner_rust_type) ; } } }); if alias_style == AliasVariation::NewTypeDeref { let prefix = ctx.trait_prefix(); tokens.append_all(quote! { impl ::#prefix::ops::Deref for #rust_name { type Target = #inner_rust_type; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl ::#prefix::ops::DerefMut for #rust_name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } }); } result.push(tokens); } TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item), TypeKind::ObjCId | TypeKind::ObjCSel => { result.saw_objc(); } TypeKind::ObjCInterface(ref interface) => { interface.codegen(ctx, result, item) } ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) } } } } struct Vtable<'a> { item_id: ItemId, /// A reference to the originating compound object. #[allow(dead_code)] comp_info: &'a CompInfo, } impl<'a> Vtable<'a> { fn new(item_id: ItemId, comp_info: &'a CompInfo) -> Self { Vtable { item_id, comp_info } } } impl<'a> CodeGenerator for Vtable<'a> { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { assert_eq!(item.id(), self.item_id); debug_assert!(item.is_enabled_for_codegen(ctx)); let name = ctx.rust_ident(self.canonical_name(ctx)); // For now, we will only generate vtables for classes that: // - do not inherit from others (compilers merge VTable from primary parent class). // - do not contain a virtual destructor (requires ordering; platforms generate different vtables). if ctx.options().vtable_generation && self.comp_info.base_members().is_empty() && self.comp_info.destructor().is_none() { let class_ident = ctx.rust_ident(self.item_id.canonical_name(ctx)); let methods = self .comp_info .methods() .iter() .filter_map(|m| { if !m.is_virtual() { return None; } let function_item = ctx.resolve_item(m.signature()); let function = function_item.expect_function(); let signature_item = ctx.resolve_item(function.signature()); let signature = match signature_item.expect_type().kind() { TypeKind::Function(ref sig) => sig, _ => panic!("Function signature type mismatch"), }; // FIXME: Is there a canonical name without the class prepended? let function_name = function_item.canonical_name(ctx); // FIXME: Need to account for overloading with times_seen (separately from regular function path). let function_name = ctx.rust_ident(function_name); let mut args = utils::fnsig_arguments(ctx, signature); let ret = utils::fnsig_return_ty(ctx, signature); args[0] = if m.is_const() { quote! { this: *const #class_ident } } else { quote! { this: *mut #class_ident } }; Some(quote! { pub #function_name : unsafe extern "C" fn( #( #args ),* ) #ret }) }) .collect::>(); result.push(quote! { #[repr(C)] pub struct #name { #( #methods ),* } }) } else { // For the cases we don't support, simply generate an empty struct. let void = helpers::ast_ty::c_void(ctx); result.push(quote! { #[repr(C)] pub struct #name ( #void ); }); } } } impl<'a> ItemCanonicalName for Vtable<'a> { fn canonical_name(&self, ctx: &BindgenContext) -> String { format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) } } impl<'a> TryToRustTy for Vtable<'a> { type Extra = (); fn try_to_rust_ty( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { let name = ctx.rust_ident(self.canonical_name(ctx)); Ok(syn::parse_quote! { #name }) } } impl CodeGenerator for TemplateInstantiation { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug_assert!(item.is_enabled_for_codegen(ctx)); // Although uses of instantiations don't need code generation, and are // just converted to rust types in fields, vars, etc, we take this // opportunity to generate tests for their layout here. If the // instantiation is opaque, then its presumably because we don't // properly understand it (maybe because of specializations), and so we // shouldn't emit layout tests either. if !ctx.options().layout_tests || self.is_opaque(ctx, item) { return; } // If there are any unbound type parameters, then we can't generate a // layout test because we aren't dealing with a concrete type with a // concrete size and alignment. if ctx.uses_any_template_parameters(item.id()) { return; } let layout = item.kind().expect_type().layout(ctx); if let Some(layout) = layout { let size = layout.size; let align = layout.align; let name = item.full_disambiguated_name(ctx); let mut fn_name = format!("__bindgen_test_layout_{}_instantiation", name); let times_seen = result.overload_number(&fn_name); if times_seen > 0 { write!(&mut fn_name, "_{}", times_seen).unwrap(); } let fn_name = ctx.rust_ident_raw(fn_name); let prefix = ctx.trait_prefix(); let ident = item.to_rust_ty_or_opaque(ctx, &()); let size_of_expr = quote! { ::#prefix::mem::size_of::<#ident>() }; let align_of_expr = quote! { ::#prefix::mem::align_of::<#ident>() }; let item = quote! { #[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))); } }; result.push(item); } } } /// Trait for implementing the code generation of a struct or union field. trait FieldCodegen<'a> { type Extra; #[allow(clippy::too_many_arguments)] fn codegen( &self, ctx: &BindgenContext, visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, extra: Self::Extra, ) where F: Extend, M: Extend; } impl<'a> FieldCodegen<'a> for Field { type Extra = (); fn codegen( &self, ctx: &BindgenContext, visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, _: (), ) where F: Extend, M: Extend, { match *self { Field::DataMember(ref data) => { data.codegen( ctx, visibility_kind, accessor_kind, parent, parent_item, result, struct_layout, fields, methods, (), ); } Field::Bitfields(ref unit) => { unit.codegen( ctx, visibility_kind, accessor_kind, parent, parent_item, result, struct_layout, fields, methods, (), ); } } } } fn wrap_union_field_if_needed( ctx: &BindgenContext, struct_layout: &StructLayoutTracker, ty: syn::Type, result: &mut CodegenResult, ) -> syn::Type { if struct_layout.is_rust_union() { if struct_layout.can_copy_union_fields() { ty } else { let prefix = ctx.trait_prefix(); syn::parse_quote! { ::#prefix::mem::ManuallyDrop<#ty> } } } else { result.saw_bindgen_union(); if ctx.options().enable_cxx_namespaces { syn::parse_quote! { root::__BindgenUnionField<#ty> } } else { syn::parse_quote! { __BindgenUnionField<#ty> } } } } impl<'a> FieldCodegen<'a> for FieldData { type Extra = (); fn codegen( &self, ctx: &BindgenContext, parent_visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, _: (), ) where F: Extend, M: Extend, { // Bitfields are handled by `FieldCodegen` implementations for // `BitfieldUnit` and `Bitfield`. assert!(self.bitfield_width().is_none()); let field_item = self.ty().into_resolver().through_type_refs().resolve(ctx); let field_ty = field_item.expect_type(); let ty = self .ty() .to_rust_ty_or_opaque(ctx, &()) .with_implicit_template_params(ctx, field_item); // NB: If supported, we use proper `union` types. let ty = if parent.is_union() { wrap_union_field_if_needed(ctx, struct_layout, ty, result) } else if let Some(item) = field_ty.is_incomplete_array(ctx) { result.saw_incomplete_array(); let inner = item.to_rust_ty_or_opaque(ctx, &()); if ctx.options().enable_cxx_namespaces { syn::parse_quote! { root::__IncompleteArrayField<#inner> } } else { syn::parse_quote! { __IncompleteArrayField<#inner> } } } else { ty }; let mut field = quote! {}; if ctx.options().generate_comments { if let Some(raw_comment) = self.comment() { let comment = ctx.options().process_comment(raw_comment); field = attributes::doc(comment); } } let field_name = self .name() .map(|name| ctx.rust_mangle(name).into_owned()) .expect("Each field should have a name in codegen!"); let field_name = field_name.as_str(); let field_ident = ctx.rust_ident_raw(field_name); if let Some(padding_field) = struct_layout.saw_field(field_name, field_ty, self.offset()) { fields.extend(Some(padding_field)); } let visibility = compute_visibility( ctx, self.is_public(), ctx.options().last_callback(|cb| { cb.field_visibility(FieldInfo { type_name: &parent_item.canonical_name(ctx), field_name, }) }), self.annotations(), parent_visibility_kind, ); let accessor_kind = self.annotations().accessor_kind().unwrap_or(accessor_kind); match visibility { FieldVisibilityKind::Private => { field.append_all(quote! { #field_ident : #ty , }); } FieldVisibilityKind::PublicCrate => { field.append_all(quote! { pub(crate) #field_ident : #ty , }); } FieldVisibilityKind::Public => { field.append_all(quote! { pub #field_ident : #ty , }); } } fields.extend(Some(field)); // TODO: Factor the following code out, please! if accessor_kind == FieldAccessorKind::None { return; } let getter_name = ctx.rust_ident_raw(format!("get_{}", field_name)); let mutable_getter_name = ctx.rust_ident_raw(format!("get_{}_mut", field_name)); methods.extend(Some(match accessor_kind { FieldAccessorKind::None => unreachable!(), FieldAccessorKind::Regular => { quote! { #[inline] pub fn #getter_name(&self) -> & #ty { &self.#field_ident } #[inline] pub fn #mutable_getter_name(&mut self) -> &mut #ty { &mut self.#field_ident } } } FieldAccessorKind::Unsafe => { quote! { #[inline] pub unsafe fn #getter_name(&self) -> & #ty { &self.#field_ident } #[inline] pub unsafe fn #mutable_getter_name(&mut self) -> &mut #ty { &mut self.#field_ident } } } FieldAccessorKind::Immutable => { quote! { #[inline] pub fn #getter_name(&self) -> & #ty { &self.#field_ident } } } })); } } impl BitfieldUnit { /// Get the constructor name for this bitfield unit. fn ctor_name(&self) -> proc_macro2::TokenStream { let ctor_name = Ident::new( &format!("new_bitfield_{}", self.nth()), Span::call_site(), ); quote! { #ctor_name } } } impl Bitfield { /// Extend an under construction bitfield unit constructor with this /// bitfield. This sets the relevant bits on the `__bindgen_bitfield_unit` /// variable that's being constructed. fn extend_ctor_impl( &self, ctx: &BindgenContext, param_name: proc_macro2::TokenStream, mut ctor_impl: proc_macro2::TokenStream, ) -> proc_macro2::TokenStream { let bitfield_ty = ctx.resolve_type(self.ty()); let bitfield_ty_layout = bitfield_ty .layout(ctx) .expect("Bitfield without layout? Gah!"); let bitfield_int_ty = helpers::integer_type(ctx, bitfield_ty_layout) .expect( "Should already have verified that the bitfield is \ representable as an int", ); let offset = self.offset_into_unit(); let width = self.width() as u8; let prefix = ctx.trait_prefix(); ctor_impl.append_all(quote! { __bindgen_bitfield_unit.set( #offset, #width, { let #param_name: #bitfield_int_ty = unsafe { ::#prefix::mem::transmute(#param_name) }; #param_name as u64 } ); }); ctor_impl } } fn access_specifier( visibility: FieldVisibilityKind, ) -> proc_macro2::TokenStream { match visibility { FieldVisibilityKind::Private => quote! {}, FieldVisibilityKind::PublicCrate => quote! { pub(crate) }, FieldVisibilityKind::Public => quote! { pub }, } } /// Compute a fields or structs visibility based on multiple conditions. /// 1. If the element was declared public, and we respect such CXX accesses specs /// (context option) => By default Public, but this can be overruled by an `annotation`. /// /// 2. If the element was declared private, and we respect such CXX accesses specs /// (context option) => By default Private, but this can be overruled by an `annotation`. /// /// 3. If we do not respect visibility modifiers, the result depends on the `annotation`, /// if any, or the passed `default_kind`. /// fn compute_visibility( ctx: &BindgenContext, is_declared_public: bool, callback_override: Option, annotations: &Annotations, default_kind: FieldVisibilityKind, ) -> FieldVisibilityKind { callback_override .or_else(|| annotations.visibility_kind()) .unwrap_or_else(|| { match (is_declared_public, ctx.options().respect_cxx_access_specs) { (true, true) => { // declared as public, cxx specs are respected FieldVisibilityKind::Public } (false, true) => { // declared as private, cxx specs are respected FieldVisibilityKind::Private } (_, false) => { // cxx specs are not respected, declaration does not matter. default_kind } } }) } impl<'a> FieldCodegen<'a> for BitfieldUnit { type Extra = (); fn codegen( &self, ctx: &BindgenContext, visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, _: (), ) where F: Extend, M: Extend, { use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT; result.saw_bitfield_unit(); let layout = self.layout(); let unit_field_ty = helpers::bitfield_unit(ctx, layout); let field_ty = { let unit_field_ty = unit_field_ty.clone(); if parent.is_union() { wrap_union_field_if_needed( ctx, struct_layout, unit_field_ty, result, ) } else { unit_field_ty } }; { let align_field_name = format!("_bitfield_align_{}", self.nth()); let align_field_ident = ctx.rust_ident(align_field_name); let align_ty = match self.layout().align { n if n >= 8 => quote! { u64 }, 4 => quote! { u32 }, 2 => quote! { u16 }, _ => quote! { u8 }, }; let access_spec = access_specifier(visibility_kind); let align_field = quote! { #access_spec #align_field_ident: [#align_ty; 0], }; fields.extend(Some(align_field)); } let unit_field_name = format!("_bitfield_{}", self.nth()); let unit_field_ident = ctx.rust_ident(&unit_field_name); let ctor_name = self.ctor_name(); let mut ctor_params = vec![]; let mut ctor_impl = quote! {}; // We cannot generate any constructor if the underlying storage can't // implement AsRef<[u8]> / AsMut<[u8]> / etc, or can't derive Default. // // We don't check `larger_arrays` here because Default does still have // the 32 items limitation. let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT; let mut unit_visibility = visibility_kind; for bf in self.bitfields() { // Codegen not allowed for anonymous bitfields if bf.name().is_none() { continue; } if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT && !ctx.options().rust_features().larger_arrays { continue; } let mut bitfield_representable_as_int = true; let mut bitfield_visibility = visibility_kind; bf.codegen( ctx, visibility_kind, accessor_kind, parent, parent_item, result, struct_layout, fields, methods, ( &unit_field_name, &mut bitfield_representable_as_int, &mut bitfield_visibility, ), ); if bitfield_visibility < unit_visibility { unit_visibility = bitfield_visibility; } // Generating a constructor requires the bitfield to be representable as an integer. if !bitfield_representable_as_int { generate_ctor = false; continue; } let param_name = bitfield_getter_name(ctx, bf); let bitfield_ty_item = ctx.resolve_item(bf.ty()); let bitfield_ty = bitfield_ty_item.expect_type(); let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); ctor_params.push(quote! { #param_name : #bitfield_ty }); ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl); } let access_spec = access_specifier(unit_visibility); let field = quote! { #access_spec #unit_field_ident : #field_ty , }; fields.extend(Some(field)); if generate_ctor { methods.extend(Some(quote! { #[inline] #access_spec fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty { let mut __bindgen_bitfield_unit: #unit_field_ty = Default::default(); #ctor_impl __bindgen_bitfield_unit } })); } struct_layout.saw_bitfield_unit(layout); } } fn bitfield_getter_name( ctx: &BindgenContext, bitfield: &Bitfield, ) -> proc_macro2::TokenStream { let name = bitfield.getter_name(); let name = ctx.rust_ident_raw(name); quote! { #name } } fn bitfield_setter_name( ctx: &BindgenContext, bitfield: &Bitfield, ) -> proc_macro2::TokenStream { let setter = bitfield.setter_name(); let setter = ctx.rust_ident_raw(setter); quote! { #setter } } impl<'a> FieldCodegen<'a> for Bitfield { type Extra = (&'a str, &'a mut bool, &'a mut FieldVisibilityKind); fn codegen( &self, ctx: &BindgenContext, visibility_kind: FieldVisibilityKind, _accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, _result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, _fields: &mut F, methods: &mut M, (unit_field_name, bitfield_representable_as_int, bitfield_visibility): ( &'a str, &mut bool, &'a mut FieldVisibilityKind, ), ) where F: Extend, M: Extend, { let prefix = ctx.trait_prefix(); let getter_name = bitfield_getter_name(ctx, self); let setter_name = bitfield_setter_name(ctx, self); let unit_field_ident = Ident::new(unit_field_name, Span::call_site()); let bitfield_ty_item = ctx.resolve_item(self.ty()); let bitfield_ty = bitfield_ty_item.expect_type(); let bitfield_ty_layout = bitfield_ty .layout(ctx) .expect("Bitfield without layout? Gah!"); let bitfield_int_ty = match helpers::integer_type(ctx, bitfield_ty_layout) { Some(int_ty) => { *bitfield_representable_as_int = true; int_ty } None => { *bitfield_representable_as_int = false; return; } }; let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); let offset = self.offset_into_unit(); let width = self.width() as u8; let override_visibility = self.name().and_then(|field_name| { ctx.options().last_callback(|cb| { cb.field_visibility(FieldInfo { type_name: &parent_item.canonical_name(ctx), field_name, }) }) }); *bitfield_visibility = compute_visibility( ctx, self.is_public(), override_visibility, self.annotations(), visibility_kind, ); let access_spec = access_specifier(*bitfield_visibility); if parent.is_union() && !struct_layout.is_rust_union() { methods.extend(Some(quote! { #[inline] #access_spec fn #getter_name(&self) -> #bitfield_ty { unsafe { ::#prefix::mem::transmute( self.#unit_field_ident.as_ref().get(#offset, #width) as #bitfield_int_ty ) } } #[inline] #access_spec fn #setter_name(&mut self, val: #bitfield_ty) { unsafe { let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); self.#unit_field_ident.as_mut().set( #offset, #width, val as u64 ) } } })); } else { methods.extend(Some(quote! { #[inline] #access_spec fn #getter_name(&self) -> #bitfield_ty { unsafe { ::#prefix::mem::transmute( self.#unit_field_ident.get(#offset, #width) as #bitfield_int_ty ) } } #[inline] #access_spec fn #setter_name(&mut self, val: #bitfield_ty) { unsafe { let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); self.#unit_field_ident.set( #offset, #width, val as u64 ) } } })); } } } impl CodeGenerator for CompInfo { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug!("::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); // 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 ty = item.expect_type(); let layout = ty.layout(ctx); let mut packed = self.is_packed(ctx, layout.as_ref()); let canonical_name = item.canonical_name(ctx); let canonical_ident = ctx.rust_ident(&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 // HasVtable::has_vtable_ptr is false but HasVtable::has_vtable is true. // // Also, we need to generate the vtable in such a way it "inherits" from // the parent too. let is_opaque = item.is_opaque(ctx, &()); let mut fields = vec![]; let visibility = item .annotations() .visibility_kind() .unwrap_or(ctx.options().default_visibility); let mut struct_layout = StructLayoutTracker::new( ctx, self, ty, &canonical_name, visibility, packed, ); if !is_opaque { if item.has_vtable_ptr(ctx) { let vtable = Vtable::new(item.id(), self); vtable.codegen(ctx, result, item); let vtable_type = vtable .try_to_rust_ty(ctx, &()) .expect("vtable to Rust type conversion is infallible") .to_ptr(true); fields.push(quote! { pub vtable_: #vtable_type , }); struct_layout.saw_vtable(); } for base in self.base_members() { if !base.requires_storage(ctx) { continue; } let inner_item = ctx.resolve_item(base.ty); let inner = inner_item .to_rust_ty_or_opaque(ctx, &()) .with_implicit_template_params(ctx, inner_item); let field_name = ctx.rust_ident(&base.field_name); struct_layout.saw_base(inner_item.expect_type()); let visibility = match ( base.is_public(), ctx.options().respect_cxx_access_specs, ) { (true, true) => FieldVisibilityKind::Public, (false, true) => FieldVisibilityKind::Private, _ => ctx.options().default_visibility, }; let access_spec = access_specifier(visibility); fields.push(quote! { #access_spec #field_name: #inner, }); } } let mut methods = vec![]; if !is_opaque { let struct_accessor_kind = item .annotations() .accessor_kind() .unwrap_or(FieldAccessorKind::None); for field in self.fields() { field.codegen( ctx, visibility, struct_accessor_kind, self, item, result, &mut struct_layout, &mut fields, &mut methods, (), ); } // Check whether an explicit padding field is needed // at the end. if let Some(comp_layout) = layout { fields.extend( struct_layout .add_tail_padding(&canonical_name, comp_layout), ); } } if is_opaque { // Opaque item should not have generated methods, fields. debug_assert!(fields.is_empty()); debug_assert!(methods.is_empty()); } let is_union = self.kind() == CompKind::Union; let layout = item.kind().expect_type().layout(ctx); let zero_sized = item.is_zero_sized(ctx); let forward_decl = self.is_forward_declaration(); let mut explicit_align = None; // C++ requires every struct to be addressable, so what C++ compilers do // is making the struct 1-byte sized. // // This is apparently not the case for C, see: // https://github.com/rust-lang/rust-bindgen/issues/551 // // Just get the layout, and assume C++ if not. // // NOTE: This check is conveniently here to avoid the dummy fields we // may add for unused template parameters. if !forward_decl && zero_sized { let has_address = if is_opaque { // Generate the address field if it's an opaque type and // couldn't determine the layout of the blob. layout.is_none() } else { layout.map_or(true, |l| l.size != 0) }; if has_address { let layout = Layout::new(1, 1); let ty = helpers::blob(ctx, Layout::new(1, 1)); struct_layout.saw_field_with_layout( "_address", layout, /* offset = */ Some(0), ); fields.push(quote! { pub _address: #ty, }); } } if is_opaque { match layout { Some(l) => { explicit_align = Some(l.align); let ty = helpers::blob(ctx, l); fields.push(quote! { pub _bindgen_opaque_blob: #ty , }); } None => { warn!("Opaque type without layout! Expect dragons!"); } } } else if !is_union && !zero_sized { if let Some(padding_field) = layout.and_then(|layout| struct_layout.pad_struct(layout)) { fields.push(padding_field); } if let Some(layout) = layout { if struct_layout.requires_explicit_align(layout) { if layout.align == 1 { packed = true; } else { explicit_align = Some(layout.align); if !ctx.options().rust_features.repr_align { let ty = helpers::blob( ctx, Layout::new(0, layout.align), ); fields.push(quote! { pub __bindgen_align: #ty , }); } } } } } else if is_union && !forward_decl { // TODO(emilio): It'd be nice to unify this with the struct path // above somehow. let layout = layout.expect("Unable to get layout information?"); if struct_layout.requires_explicit_align(layout) { explicit_align = Some(layout.align); } if !struct_layout.is_rust_union() { let ty = helpers::blob(ctx, layout); fields.push(quote! { pub bindgen_union_field: #ty , }) } } if forward_decl { fields.push(quote! { _unused: [u8; 0], }); } let mut generic_param_names = vec![]; for (idx, ty) in item.used_template_params(ctx).iter().enumerate() { let param = ctx.resolve_type(*ty); let name = param.name().unwrap(); let ident = ctx.rust_ident(name); generic_param_names.push(ident.clone()); let prefix = ctx.trait_prefix(); let field_name = ctx.rust_ident(format!("_phantom_{}", idx)); fields.push(quote! { pub #field_name : ::#prefix::marker::PhantomData< ::#prefix::cell::UnsafeCell<#ident> > , }); } let generics = if !generic_param_names.is_empty() { let generic_param_names = generic_param_names.clone(); quote! { < #( #generic_param_names ),* > } } else { quote! {} }; let mut attributes = vec![]; let mut needs_clone_impl = false; let mut needs_default_impl = false; let mut needs_debug_impl = false; let mut needs_partialeq_impl = false; if let Some(comment) = item.comment(ctx) { attributes.push(attributes::doc(comment)); } // if a type has both a "packed" attribute and an "align(N)" attribute, then check if the // "packed" attr is redundant, and do not include it if so. if packed && !is_opaque && !(explicit_align.is_some() && self.already_packed(ctx).unwrap_or(false)) { let n = layout.map_or(1, |l| l.align); assert!(ctx.options().rust_features().repr_packed_n || n == 1); let packed_repr = if n == 1 { "packed".to_string() } else { format!("packed({})", n) }; attributes.push(attributes::repr_list(&["C", &packed_repr])); } else { attributes.push(attributes::repr("C")); } if ctx.options().rust_features().repr_align { if let Some(explicit) = explicit_align { // Ensure that the struct has the correct alignment even in // presence of alignas. let explicit = helpers::ast_ty::int_expr(explicit as i64); attributes.push(quote! { #[repr(align(#explicit))] }); } } let derivable_traits = derives_of_item(item, ctx, packed); if !derivable_traits.contains(DerivableTraits::DEBUG) { needs_debug_impl = ctx.options().derive_debug && ctx.options().impl_debug && !ctx.no_debug_by_name(item) && !item.annotations().disallow_debug(); } if !derivable_traits.contains(DerivableTraits::DEFAULT) { needs_default_impl = ctx.options().derive_default && !self.is_forward_declaration() && !ctx.no_default_by_name(item) && !item.annotations().disallow_default(); } let all_template_params = item.all_template_params(ctx); if derivable_traits.contains(DerivableTraits::COPY) && !derivable_traits.contains(DerivableTraits::CLONE) { needs_clone_impl = true; } if !derivable_traits.contains(DerivableTraits::PARTIAL_EQ) { needs_partialeq_impl = ctx.options().derive_partialeq && ctx.options().impl_partialeq && ctx.lookup_can_derive_partialeq_or_partialord(item.id()) == CanDerive::Manually; } let mut derives: Vec<_> = derivable_traits.into(); derives.extend(item.annotations().derives().iter().map(String::as_str)); let is_rust_union = is_union && struct_layout.is_rust_union(); // The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives = ctx.options().all_callbacks(|cb| { cb.add_derives(&DeriveInfo { name: &canonical_name, kind: if is_rust_union { DeriveTypeKind::Union } else { DeriveTypeKind::Struct }, }) }); // In most cases this will be a no-op, since custom_derives will be empty. derives.extend(custom_derives.iter().map(|s| s.as_str())); if !derives.is_empty() { attributes.push(attributes::derives(&derives)) } if item.must_use(ctx) { attributes.push(attributes::must_use()); } let mut tokens = if is_rust_union { quote! { #( #attributes )* pub union #canonical_ident } } else { quote! { #( #attributes )* pub struct #canonical_ident } }; tokens.append_all(quote! { #generics { #( #fields )* } }); result.push(tokens); // 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, &()); } // 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 unknown attribute that may affect layout", canonical_ident ); } if all_template_params.is_empty() { if !is_opaque { for var in self.inner_vars() { ctx.resolve_item(*var).codegen(ctx, result, &()); } } if ctx.options().layout_tests && !self.is_forward_declaration() { if let Some(layout) = layout { let fn_name = format!("bindgen_test_layout_{}", canonical_ident); let fn_name = ctx.rust_ident_raw(fn_name); let prefix = ctx.trait_prefix(); let size_of_expr = quote! { ::#prefix::mem::size_of::<#canonical_ident>() }; let align_of_expr = quote! { ::#prefix::mem::align_of::<#canonical_ident>() }; let size = layout.size; let align = layout.align; let check_struct_align = if align > ctx.target_pointer_size() && !ctx.options().rust_features().repr_align { None } else { Some(quote! { assert_eq!(#align_of_expr, #align, concat!("Alignment of ", stringify!(#canonical_ident))); }) }; let should_skip_field_offset_checks = is_opaque; let check_field_offset = if should_skip_field_offset_checks { vec![] } else { self.fields() .iter() .filter_map(|field| match *field { Field::DataMember(ref f) if f.name().is_some() => Some(f), _ => None, }) .flat_map(|field| { let name = field.name().unwrap(); field.offset().map(|offset| { let field_offset = offset / 8; let field_name = ctx.rust_ident(name); quote! { assert_eq!( unsafe { ::#prefix::ptr::addr_of!((*ptr).#field_name) as usize - ptr as usize }, #field_offset, concat!("Offset of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name)) ); } }) }) .collect() }; let uninit_decl = if !check_field_offset.is_empty() { // FIXME: When MSRV >= 1.59.0, we can use // > const PTR: *const #canonical_ident = ::#prefix::mem::MaybeUninit::uninit().as_ptr(); Some(quote! { // Use a shared MaybeUninit so that rustc with // opt-level=0 doesn't take too much stack space, // see #2218. const UNINIT: ::#prefix::mem::MaybeUninit<#canonical_ident> = ::#prefix::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr(); }) } else { None }; let item = quote! { #[test] fn #fn_name() { #uninit_decl assert_eq!(#size_of_expr, #size, concat!("Size of: ", stringify!(#canonical_ident))); #check_struct_align #( #check_field_offset )* } }; 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, 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, self, ); } } if ctx.options().codegen_config.destructors() { if let Some((kind, destructor)) = self.destructor() { debug_assert!(kind.is_destructor()); Method::new(kind, destructor, false).codegen_method( ctx, &mut methods, &mut method_names, result, 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 = quote! { #canonical_ident #generics }; if needs_clone_impl { result.push(quote! { impl #generics Clone for #ty_for_impl { fn clone(&self) -> Self { *self } } }); } if needs_default_impl { let prefix = ctx.trait_prefix(); let body = if ctx.options().rust_features().maybe_uninit { quote! { let mut s = ::#prefix::mem::MaybeUninit::::uninit(); unsafe { ::#prefix::ptr::write_bytes(s.as_mut_ptr(), 0, 1); s.assume_init() } } } else { quote! { unsafe { let mut s: Self = ::#prefix::mem::uninitialized(); ::#prefix::ptr::write_bytes(&mut s, 0, 1); s } } }; // Note we use `ptr::write_bytes()` instead of `mem::zeroed()` because the latter does // not necessarily ensure padding bytes are zeroed. Some C libraries are sensitive to // non-zero padding bytes, especially when forwards/backwards compatability is // involved. result.push(quote! { impl #generics Default for #ty_for_impl { fn default() -> Self { #body } } }); } if needs_debug_impl { let impl_ = impl_debug::gen_debug_impl( ctx, self.fields(), item, self.kind(), ); let prefix = ctx.trait_prefix(); result.push(quote! { impl #generics ::#prefix::fmt::Debug for #ty_for_impl { #impl_ } }); } if needs_partialeq_impl { if let Some(impl_) = impl_partialeq::gen_partialeq_impl( ctx, self, item, &ty_for_impl, ) { let partialeq_bounds = if !generic_param_names.is_empty() { let bounds = generic_param_names.iter().map(|t| { quote! { #t: PartialEq } }); quote! { where #( #bounds ),* } } else { quote! {} }; let prefix = ctx.trait_prefix(); result.push(quote! { impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds { #impl_ } }); } } if !methods.is_empty() { result.push(quote! { impl #generics #ty_for_impl { #( #methods )* } }); } } } impl Method { fn codegen_method( &self, ctx: &BindgenContext, methods: &mut Vec, method_names: &mut HashSet, result: &mut CodegenResult<'_>, _parent: &CompInfo, ) { assert!({ let cc = &ctx.options().codegen_config; match self.kind() { MethodKind::Constructor => cc.constructors(), MethodKind::Destructor => cc.destructors(), MethodKind::VirtualDestructor { .. } => cc.destructors(), MethodKind::Static | MethodKind::Normal | MethodKind::Virtual { .. } => cc.methods(), } }); // TODO(emilio): We could generate final stuff at least. if self.is_virtual() { return; // FIXME } // First of all, output the actual function. let function_item = ctx.resolve_item(self.signature()); if !function_item.process_before_codegen(ctx, result) { return; } let function = function_item.expect_function(); let times_seen = function.codegen(ctx, result, function_item); let times_seen = match times_seen { Some(seen) => seen, None => return, }; let signature_item = ctx.resolve_item(function.signature()); let mut name = match self.kind() { MethodKind::Constructor => "new".into(), MethodKind::Destructor => "destruct".into(), _ => function.name().to_owned(), }; let signature = match *signature_item.expect_type().kind() { TypeKind::Function(ref sig) => sig, _ => panic!("How in the world?"), }; let supported_abi = signature.abi(ctx, Some(&*name)).is_ok(); if !supported_abi { return; } // 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; } if method_names.contains(&name) { let mut count = 1; let mut new_name; while { new_name = format!("{}{}", name, count); method_names.contains(&new_name) } { count += 1; } name = new_name; } method_names.insert(name.clone()); let mut function_name = function_item.canonical_name(ctx); if times_seen > 0 { write!(&mut function_name, "{}", times_seen).unwrap(); } let function_name = ctx.rust_ident(function_name); let mut args = utils::fnsig_arguments(ctx, signature); let mut ret = utils::fnsig_return_ty(ctx, signature); if !self.is_static() && !self.is_constructor() { args[0] = if self.is_const() { quote! { &self } } else { quote! { &mut self } }; } // 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() { args.remove(0); ret = quote! { -> Self }; } 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 = if ctx .options() .rust_features() .maybe_uninit { exprs[0] = quote! { __bindgen_tmp.as_mut_ptr() }; quote! { let mut __bindgen_tmp = ::#prefix::mem::MaybeUninit::uninit() } } else { exprs[0] = quote! { &mut __bindgen_tmp }; quote! { let mut __bindgen_tmp = ::#prefix::mem::uninitialized() } }; stmts.push(tmp_variable_decl); } else if !self.is_static() { assert!(!exprs.is_empty()); exprs[0] = quote! { self }; }; let call = quote! { #function_name (#( #exprs ),* ) }; stmts.push(call); if self.is_constructor() { stmts.push(if ctx.options().rust_features().maybe_uninit { quote! { __bindgen_tmp.assume_init() } } else { quote! { __bindgen_tmp } }) } let block = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*)); let mut attrs = vec![attributes::inline()]; if signature.must_use() && ctx.options().rust_features().must_use_function { attrs.push(attributes::must_use()); } let name = ctx.rust_ident(&name); methods.push(quote! { #(#attrs)* pub unsafe fn #name ( #( #args ),* ) #ret { #block } }); } } /// A helper type that represents different enum variations. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum EnumVariation { /// The code for this enum will use a Rust enum. Note that creating this in unsafe code /// (including FFI) with an invalid value will invoke undefined behaviour, whether or not /// its marked as non_exhaustive. Rust { /// Indicates whether the generated struct should be `#[non_exhaustive]` non_exhaustive: bool, }, /// The code for this enum will use a newtype NewType { /// Indicates whether the newtype will have bitwise operators is_bitfield: bool, /// Indicates whether the variants will be represented as global constants is_global: bool, }, /// The code for this enum will use consts Consts, /// The code for this enum will use a module containing consts ModuleConsts, } impl EnumVariation { fn is_rust(&self) -> bool { matches!(*self, EnumVariation::Rust { .. }) } /// Both the `Const` and `ModuleConsts` variants will cause this to return /// true. fn is_const(&self) -> bool { matches!(*self, EnumVariation::Consts | EnumVariation::ModuleConsts) } } impl Default for EnumVariation { fn default() -> EnumVariation { EnumVariation::Consts } } impl fmt::Display for EnumVariation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Self::Rust { non_exhaustive: false, } => "rust", Self::Rust { non_exhaustive: true, } => "rust_non_exhaustive", Self::NewType { is_bitfield: true, .. } => "bitfield", Self::NewType { is_bitfield: false, is_global, } => { if *is_global { "newtype_global" } else { "newtype" } } Self::Consts => "consts", Self::ModuleConsts => "moduleconsts", }; s.fmt(f) } } impl std::str::FromStr for EnumVariation { type Err = std::io::Error; /// Create a `EnumVariation` from a string. fn from_str(s: &str) -> Result { match s { "rust" => Ok(EnumVariation::Rust { non_exhaustive: false, }), "rust_non_exhaustive" => Ok(EnumVariation::Rust { non_exhaustive: true, }), "bitfield" => Ok(EnumVariation::NewType { is_bitfield: true, is_global: false, }), "consts" => Ok(EnumVariation::Consts), "moduleconsts" => Ok(EnumVariation::ModuleConsts), "newtype" => Ok(EnumVariation::NewType { is_bitfield: false, is_global: false, }), "newtype_global" => Ok(EnumVariation::NewType { is_bitfield: false, is_global: true, }), _ => Err(std::io::Error::new( std::io::ErrorKind::InvalidInput, concat!( "Got an invalid EnumVariation. Accepted values ", "are 'rust', 'rust_non_exhaustive', 'bitfield', 'consts',", "'moduleconsts', 'newtype' and 'newtype_global'." ), )), } } } /// A helper type to construct different enum variations. enum EnumBuilder<'a> { Rust { attrs: Vec, ident: Ident, tokens: proc_macro2::TokenStream, emitted_any_variants: bool, }, NewType { canonical_name: &'a str, tokens: proc_macro2::TokenStream, is_bitfield: bool, is_global: bool, }, Consts { variants: Vec, }, ModuleConsts { module_name: &'a str, module_items: Vec, }, } impl<'a> EnumBuilder<'a> { /// Returns true if the builder is for a rustified enum. fn is_rust_enum(&self) -> bool { matches!(*self, EnumBuilder::Rust { .. }) } /// Create a new enum given an item builder, a canonical name, a name for /// the representation, and which variation it should be generated as. fn new( name: &'a str, mut attrs: Vec, repr: syn::Type, enum_variation: EnumVariation, has_typedef: bool, ) -> Self { let ident = Ident::new(name, Span::call_site()); match enum_variation { EnumVariation::NewType { is_bitfield, is_global, } => EnumBuilder::NewType { canonical_name: name, tokens: quote! { #( #attrs )* pub struct #ident (pub #repr); }, is_bitfield, is_global, }, EnumVariation::Rust { .. } => { // `repr` is guaranteed to be Rustified in Enum::codegen attrs.insert(0, quote! { #[repr( #repr )] }); let tokens = quote!(); EnumBuilder::Rust { attrs, ident, tokens, emitted_any_variants: false, } } EnumVariation::Consts => { let mut variants = Vec::new(); if !has_typedef { variants.push(quote! { #( #attrs )* pub type #ident = #repr; }); } EnumBuilder::Consts { variants } } EnumVariation::ModuleConsts => { let ident = Ident::new( CONSTIFIED_ENUM_MODULE_REPR_NAME, Span::call_site(), ); let type_definition = quote! { #( #attrs )* pub type #ident = #repr; }; EnumBuilder::ModuleConsts { module_name: name, module_items: vec![type_definition], } } } } /// Add a variant to this enum. fn with_variant( self, ctx: &BindgenContext, variant: &EnumVariant, mangling_prefix: Option<&str>, rust_ty: syn::Type, result: &mut CodegenResult<'_>, is_ty_named: bool, ) -> Self { let variant_name = ctx.rust_mangle(variant.name()); let is_rust_enum = self.is_rust_enum(); let expr = match variant.val() { EnumVariantValue::Boolean(v) if is_rust_enum => { helpers::ast_ty::uint_expr(v as u64) } EnumVariantValue::Boolean(v) => quote!(#v), EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), EnumVariantValue::Unsigned(v) => helpers::ast_ty::uint_expr(v), }; let mut doc = quote! {}; if ctx.options().generate_comments { if let Some(raw_comment) = variant.comment() { let comment = ctx.options().process_comment(raw_comment); doc = attributes::doc(comment); } } match self { EnumBuilder::Rust { attrs, ident, tokens, emitted_any_variants: _, } => { let name = ctx.rust_ident(variant_name); EnumBuilder::Rust { attrs, ident, tokens: quote! { #tokens #doc #name = #expr, }, emitted_any_variants: true, } } EnumBuilder::NewType { canonical_name, is_global, .. } => { if ctx.options().rust_features().associated_const && is_ty_named && !is_global { let enum_ident = ctx.rust_ident(canonical_name); let variant_ident = ctx.rust_ident(variant_name); result.push(quote! { impl #enum_ident { #doc pub const #variant_ident : #rust_ty = #rust_ty ( #expr ); } }); } else { let ident = ctx.rust_ident(match mangling_prefix { Some(prefix) => { Cow::Owned(format!("{}_{}", prefix, variant_name)) } None => variant_name, }); result.push(quote! { #doc pub const #ident : #rust_ty = #rust_ty ( #expr ); }); } self } EnumBuilder::Consts { .. } => { let constant_name = match mangling_prefix { Some(prefix) => { Cow::Owned(format!("{}_{}", prefix, variant_name)) } None => variant_name, }; let ident = ctx.rust_ident(constant_name); result.push(quote! { #doc pub const #ident : #rust_ty = #expr ; }); self } EnumBuilder::ModuleConsts { module_name, mut module_items, } => { let name = ctx.rust_ident(variant_name); let ty = ctx.rust_ident(CONSTIFIED_ENUM_MODULE_REPR_NAME); module_items.push(quote! { #doc pub const #name : #ty = #expr ; }); EnumBuilder::ModuleConsts { module_name, module_items, } } } } fn build( self, ctx: &BindgenContext, rust_ty: syn::Type, result: &mut CodegenResult<'_>, ) -> proc_macro2::TokenStream { match self { EnumBuilder::Rust { attrs, ident, tokens, emitted_any_variants, .. } => { let variants = if !emitted_any_variants { quote!(__bindgen_cannot_repr_c_on_empty_enum = 0) } else { tokens }; quote! { #( #attrs )* pub enum #ident { #variants } } } EnumBuilder::NewType { canonical_name, tokens, is_bitfield, .. } => { if !is_bitfield { return tokens; } let rust_ty_name = ctx.rust_ident_raw(canonical_name); let prefix = ctx.trait_prefix(); result.push(quote! { 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) } } }); result.push(quote! { impl ::#prefix::ops::BitOrAssign for #rust_ty { #[inline] fn bitor_assign(&mut self, rhs: #rust_ty) { self.0 |= rhs.0; } } }); result.push(quote! { impl ::#prefix::ops::BitAnd<#rust_ty> for #rust_ty { type Output = Self; #[inline] fn bitand(self, other: Self) -> Self { #rust_ty_name(self.0 & other.0) } } }); result.push(quote! { impl ::#prefix::ops::BitAndAssign for #rust_ty { #[inline] fn bitand_assign(&mut self, rhs: #rust_ty) { self.0 &= rhs.0; } } }); tokens } EnumBuilder::Consts { variants, .. } => quote! { #( #variants )* }, EnumBuilder::ModuleConsts { module_items, module_name, .. } => { let ident = ctx.rust_ident(module_name); quote! { pub mod #ident { #( #module_items )* } } } } } } impl CodeGenerator for Enum { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug!("::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); let name = item.canonical_name(ctx); let ident = ctx.rust_ident(&name); let enum_ty = item.expect_type(); let layout = enum_ty.layout(ctx); let variation = self.computed_enum_variation(ctx, item); let repr_translated; let repr = match self.repr().map(|repr| ctx.resolve_type(repr)) { Some(repr) if !ctx.options().translate_enum_integer_types && !variation.is_rust() => { repr } repr => { // An enum's integer type is translated to a native Rust // integer type in 3 cases: // * the enum is Rustified and we need a translated type for // the repr attribute // * the representation couldn't be determined from the C source // * it was explicitly requested as a bindgen option let kind = 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 = kind.is_signed(); let size = layout .map(|l| l.size) .or_else(|| kind.known_size()) .unwrap_or(0); let translated = match (signed, size) { (true, 1) => IntKind::I8, (false, 1) => IntKind::U8, (true, 2) => IntKind::I16, (false, 2) => IntKind::U16, (true, 4) => IntKind::I32, (false, 4) => IntKind::U32, (true, 8) => IntKind::I64, (false, 8) => IntKind::U64, _ => { warn!( "invalid enum decl: signed: {}, size: {}", signed, size ); IntKind::I32 } }; repr_translated = Type::new(None, None, TypeKind::Int(translated), false); &repr_translated } }; let mut attrs = vec![]; // TODO(emilio): Delegate this to the builders? match variation { EnumVariation::Rust { non_exhaustive } => { if non_exhaustive && ctx.options().rust_features().non_exhaustive { attrs.push(attributes::non_exhaustive()); } else if non_exhaustive && !ctx.options().rust_features().non_exhaustive { panic!("The rust target you're using doesn't seem to support non_exhaustive enums"); } } EnumVariation::NewType { .. } => { if ctx.options().rust_features.repr_transparent { attrs.push(attributes::repr("transparent")); } else { attrs.push(attributes::repr("C")); } } _ => {} }; if let Some(comment) = item.comment(ctx) { attrs.push(attributes::doc(comment)); } if item.must_use(ctx) { attrs.push(attributes::must_use()); } if !variation.is_const() { let packed = false; // Enums can't be packed in Rust. let mut derives = derives_of_item(item, ctx, packed); // For backwards compat, enums always derive // Clone/Eq/PartialEq/Hash, even if we don't generate those by // default. derives.insert( DerivableTraits::CLONE | DerivableTraits::HASH | DerivableTraits::PARTIAL_EQ | DerivableTraits::EQ, ); let mut derives: Vec<_> = derives.into(); for derive in item.annotations().derives().iter() { if !derives.contains(&derive.as_str()) { derives.push(derive); } } // The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives = ctx.options().all_callbacks(|cb| { cb.add_derives(&DeriveInfo { name: &name, kind: DeriveTypeKind::Enum, }) }); // In most cases this will be a no-op, since custom_derives will be empty. derives.extend(custom_derives.iter().map(|s| s.as_str())); attrs.push(attributes::derives(&derives)); } fn add_constant( ctx: &BindgenContext, enum_: &Type, // Only to avoid recomputing every time. enum_canonical_name: &Ident, // May be the same as "variant" if it's because the // enum is unnamed and we still haven't seen the // value. variant_name: &Ident, referenced_name: &Ident, enum_rust_ty: syn::Type, result: &mut CodegenResult<'_>, ) { let constant_name = if enum_.name().is_some() { if ctx.options().prepend_enum_name { format!("{}_{}", enum_canonical_name, variant_name) } else { format!("{}", variant_name) } } else { format!("{}", variant_name) }; let constant_name = ctx.rust_ident(constant_name); result.push(quote! { pub const #constant_name : #enum_rust_ty = #enum_canonical_name :: #referenced_name ; }); } let repr = repr.to_rust_ty_or_opaque(ctx, item); let has_typedef = ctx.is_enum_typedef_combo(item.id()); let mut builder = EnumBuilder::new(&name, attrs, repr, variation, has_typedef); // A map where we keep a value -> variant relation. let mut seen_values = HashMap::<_, Ident>::default(); let enum_rust_ty = item.to_rust_ty_or_opaque(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 ctx.options().prepend_enum_name { if enum_ty.name().is_none() { parent_canonical_name.as_deref() } else { Some(&*name) } } else { None }; // 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 variation.is_rust() { 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(); // Use associated constants for named enums. if enum_ty.name().is_some() && ctx.options().rust_features().associated_const { let enum_canonical_name = &ident; let variant_name = ctx.rust_ident_raw(&*mangled_name); result.push(quote! { impl #enum_rust_ty { pub const #variant_name : #enum_rust_ty = #enum_canonical_name :: #existing_variant_name ; } }); } else { add_constant( ctx, enum_ty, &ident, &Ident::new(&mangled_name, Span::call_site()), existing_variant_name, enum_rust_ty.clone(), result, ); } } else { builder = builder.with_variant( ctx, variant, constant_mangling_prefix, enum_rust_ty.clone(), result, enum_ty.name().is_some(), ); } } Entry::Vacant(entry) => { builder = builder.with_variant( ctx, variant, constant_mangling_prefix, enum_rust_ty.clone(), result, enum_ty.name().is_some(), ); let variant_name = ctx.rust_ident(variant.name()); // If it's an unnamed enum, or constification is enforced, // we also generate a constant so it can be properly // accessed. if (variation.is_rust() && 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(); Ident::new( &format!("{}_{}", parent_name, variant_name), Span::call_site(), ) }; add_constant( ctx, enum_ty, &ident, &mangled_name, &variant_name, enum_rust_ty.clone(), result, ); } entry.insert(variant_name); } } } let item = builder.build(ctx, enum_rust_ty, result); result.push(item); } } /// Enum for the default type of macro constants. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum MacroTypeVariation { /// Use i32 or i64 Signed, /// Use u32 or u64 Unsigned, } impl fmt::Display for MacroTypeVariation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Self::Signed => "signed", Self::Unsigned => "unsigned", }; s.fmt(f) } } impl Default for MacroTypeVariation { fn default() -> MacroTypeVariation { MacroTypeVariation::Unsigned } } impl std::str::FromStr for MacroTypeVariation { type Err = std::io::Error; /// Create a `MacroTypeVariation` from a string. fn from_str(s: &str) -> Result { match s { "signed" => Ok(MacroTypeVariation::Signed), "unsigned" => Ok(MacroTypeVariation::Unsigned), _ => Err(std::io::Error::new( std::io::ErrorKind::InvalidInput, concat!( "Got an invalid MacroTypeVariation. Accepted values ", "are 'signed' and 'unsigned'" ), )), } } } /// Enum for how aliases should be translated. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AliasVariation { /// Convert to regular Rust alias TypeAlias, /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)] NewType, /// Same as NewStruct but also impl Deref to be able to use the methods of the wrapped type NewTypeDeref, } impl fmt::Display for AliasVariation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Self::TypeAlias => "type_alias", Self::NewType => "new_type", Self::NewTypeDeref => "new_type_deref", }; s.fmt(f) } } impl Default for AliasVariation { fn default() -> AliasVariation { AliasVariation::TypeAlias } } impl std::str::FromStr for AliasVariation { type Err = std::io::Error; /// Create an `AliasVariation` from a string. fn from_str(s: &str) -> Result { match s { "type_alias" => Ok(AliasVariation::TypeAlias), "new_type" => Ok(AliasVariation::NewType), "new_type_deref" => Ok(AliasVariation::NewTypeDeref), _ => Err(std::io::Error::new( std::io::ErrorKind::InvalidInput, concat!( "Got an invalid AliasVariation. Accepted values ", "are 'type_alias', 'new_type', and 'new_type_deref'" ), )), } } } /// Enum for how non-`Copy` `union`s should be translated. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum NonCopyUnionStyle { /// Wrap members in a type generated by `bindgen`. BindgenWrapper, /// Wrap members in [`::core::mem::ManuallyDrop`]. /// /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your /// MSRV is lower. ManuallyDrop, } impl fmt::Display for NonCopyUnionStyle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Self::BindgenWrapper => "bindgen_wrapper", Self::ManuallyDrop => "manually_drop", }; s.fmt(f) } } impl Default for NonCopyUnionStyle { fn default() -> Self { Self::BindgenWrapper } } impl std::str::FromStr for NonCopyUnionStyle { type Err = std::io::Error; fn from_str(s: &str) -> Result { match s { "bindgen_wrapper" => Ok(Self::BindgenWrapper), "manually_drop" => Ok(Self::ManuallyDrop), _ => Err(std::io::Error::new( std::io::ErrorKind::InvalidInput, concat!( "Got an invalid NonCopyUnionStyle. Accepted values ", "are 'bindgen_wrapper' and 'manually_drop'" ), )), } } } /// Fallible conversion to an opaque blob. /// /// Implementors of this trait should provide the `try_get_layout` method to /// fallibly get this thing's layout, which the provided `try_to_opaque` trait /// method will use to convert the `Layout` into an opaque blob Rust type. pub(crate) trait TryToOpaque { type Extra; /// Get the layout for this thing, if one is available. fn try_get_layout( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> error::Result; /// Do not override this provided trait method. fn try_to_opaque( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> error::Result { self.try_get_layout(ctx, extra) .map(|layout| helpers::blob(ctx, layout)) } } /// Infallible conversion of an IR thing to an opaque blob. /// /// The resulting layout is best effort, and is unfortunately not guaranteed to /// be correct. When all else fails, we fall back to a single byte layout as a /// last resort, because C++ does not permit zero-sized types. See the note in /// the `ToRustTyOrOpaque` doc comment about fallible versus infallible traits /// and when each is appropriate. /// /// Don't implement this directly. Instead implement `TryToOpaque`, and then /// leverage the blanket impl for this trait. pub(crate) trait ToOpaque: TryToOpaque { fn get_layout(&self, ctx: &BindgenContext, extra: &Self::Extra) -> Layout { self.try_get_layout(ctx, extra) .unwrap_or_else(|_| Layout::for_size(ctx, 1)) } fn to_opaque( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> syn::Type { let layout = self.get_layout(ctx, extra); helpers::blob(ctx, layout) } } impl ToOpaque for T where T: TryToOpaque {} /// Fallible conversion from an IR thing to an *equivalent* Rust type. /// /// If the C/C++ construct represented by the IR thing cannot (currently) be /// represented in Rust (for example, instantiations of templates with /// const-value generic parameters) then the impl should return an `Err`. It /// should *not* attempt to return an opaque blob with the correct size and /// alignment. That is the responsibility of the `TryToOpaque` trait. pub(crate) trait TryToRustTy { type Extra; fn try_to_rust_ty( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> error::Result; } /// Fallible conversion to a Rust type or an opaque blob with the correct size /// and alignment. /// /// Don't implement this directly. Instead implement `TryToRustTy` and /// `TryToOpaque`, and then leverage the blanket impl for this trait below. pub(crate) trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { type Extra; fn try_to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &::Extra, ) -> error::Result; } impl TryToRustTyOrOpaque for T where T: TryToRustTy + TryToOpaque, { type Extra = E; fn try_to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &E, ) -> error::Result { self.try_to_rust_ty(ctx, extra).or_else(|_| { if let Ok(layout) = self.try_get_layout(ctx, extra) { Ok(helpers::blob(ctx, layout)) } else { Err(error::Error::NoLayoutForOpaqueBlob) } }) } } /// Infallible conversion to a Rust type, or an opaque blob with a best effort /// of correct size and alignment. /// /// Don't implement this directly. Instead implement `TryToRustTy` and /// `TryToOpaque`, and then leverage the blanket impl for this trait below. /// /// ### Fallible vs. Infallible Conversions to Rust Types /// /// When should one use this infallible `ToRustTyOrOpaque` trait versus the /// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait /// implementations that need to convert another thing into a Rust type or /// opaque blob in a nested manner should also use fallible trait methods and /// propagate failure up the stack. Only infallible functions and methods like /// CodeGenerator implementations should use the infallible /// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely /// we are to get a usable `Layout` even if we can't generate an equivalent Rust /// type for a C++ construct. pub(crate) trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { type Extra; fn to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &::Extra, ) -> syn::Type; } impl ToRustTyOrOpaque for T where T: TryToRustTy + ToOpaque, { type Extra = E; fn to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &E, ) -> syn::Type { self.try_to_rust_ty(ctx, extra) .unwrap_or_else(|_| self.to_opaque(ctx, extra)) } } impl TryToOpaque for T where T: Copy + Into, { type Extra = (); fn try_get_layout( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { ctx.resolve_item((*self).into()).try_get_layout(ctx, &()) } } impl TryToRustTy for T where T: Copy + Into, { type Extra = (); fn try_to_rust_ty( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { ctx.resolve_item((*self).into()).try_to_rust_ty(ctx, &()) } } impl TryToOpaque for Item { type Extra = (); fn try_get_layout( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { self.kind().expect_type().try_get_layout(ctx, self) } } impl TryToRustTy for Item { type Extra = (); fn try_to_rust_ty( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { self.kind().expect_type().try_to_rust_ty(ctx, self) } } impl TryToOpaque for Type { type Extra = Item; fn try_get_layout( &self, ctx: &BindgenContext, _: &Item, ) -> error::Result { self.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) } } impl TryToRustTy for Type { type Extra = Item; fn try_to_rust_ty( &self, ctx: &BindgenContext, item: &Item, ) -> error::Result { use self::helpers::ast_ty::*; match *self.kind() { TypeKind::Void => Ok(c_void(ctx)), // TODO: we should do something smart with nullptr, or maybe *const // c_void is enough? TypeKind::NullPtr => Ok(c_void(ctx).to_ptr(true)), TypeKind::Int(ik) => { Ok(int_kind_rust_type(ctx, ik, self.layout(ctx))) } TypeKind::Float(fk) => { Ok(float_kind_rust_type(ctx, fk, self.layout(ctx))) } TypeKind::Complex(fk) => { let float_path = float_kind_rust_type(ctx, fk, self.layout(ctx)); ctx.generated_bindgen_complex(); Ok(if ctx.options().enable_cxx_namespaces { syn::parse_quote! { root::__BindgenComplex<#float_path> } } else { syn::parse_quote! { __BindgenComplex<#float_path> } }) } TypeKind::Function(ref signature) => { // We can't rely on the sizeof(Option>) == // sizeof(NonZero<_>) optimization with opaque blobs (because // they aren't NonZero), so don't *ever* use an or_opaque // variant here. let ty = signature.try_to_rust_ty(ctx, item)?; let prefix = ctx.trait_prefix(); Ok(syn::parse_quote! { ::#prefix::option::Option<#ty> }) } TypeKind::Array(item, len) | TypeKind::Vector(item, len) => { let ty = item.try_to_rust_ty(ctx, &())?; Ok(syn::parse_quote! { [ #ty ; #len ] }) } TypeKind::Enum(..) => { let path = item.namespace_aware_canonical_path(ctx); let path = proc_macro2::TokenStream::from_str(&path.join("::")) .unwrap(); Ok(syn::parse_quote!(#path)) } TypeKind::TemplateInstantiation(ref inst) => { inst.try_to_rust_ty(ctx, item) } TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()), TypeKind::TemplateAlias(..) | TypeKind::Alias(..) | TypeKind::BlockPointer(..) => { if self.is_block_pointer() && !ctx.options().generate_block { let void = c_void(ctx); return Ok(void.to_ptr(/* is_const = */ false)); } if item.is_opaque(ctx, &()) && item.used_template_params(ctx) .into_iter() .any(|param| param.is_template_param(ctx, &())) { self.try_to_opaque(ctx, item) } else if let Some(ty) = self .name() .and_then(|name| utils::type_from_named(ctx, name)) { Ok(ty) } else { utils::build_path(item, ctx) } } TypeKind::Comp(ref info) => { let template_params = item.all_template_params(ctx); if info.has_non_type_template_params() || (item.is_opaque(ctx, &()) && !template_params.is_empty()) { return self.try_to_opaque(ctx, item); } utils::build_path(item, ctx) } TypeKind::Opaque => self.try_to_opaque(ctx, item), TypeKind::Pointer(inner) | TypeKind::Reference(inner) => { // Check that this type has the same size as the target's pointer type. let size = self.get_layout(ctx, item).size; if size != ctx.target_pointer_size() { return Err(Error::InvalidPointerSize { ty_name: self.name().unwrap_or("unknown").into(), ty_size: size, ptr_size: ctx.target_pointer_size(), }); } let is_const = ctx.resolve_type(inner).is_const(); let inner = inner.into_resolver().through_type_refs().resolve(ctx); let inner_ty = inner.expect_type(); let is_objc_pointer = matches!(inner_ty.kind(), TypeKind::ObjCInterface(..)); // Regardless if we can properly represent the inner type, we // should always generate a proper pointer here, so use // infallible conversion of the inner type. let ty = inner .to_rust_ty_or_opaque(ctx, &()) .with_implicit_template_params(ctx, inner); // Avoid the first function pointer level, since it's already // represented in Rust. if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer { Ok(ty) } else { Ok(ty.to_ptr(is_const)) } } TypeKind::TypeParam => { let name = item.canonical_name(ctx); let ident = ctx.rust_ident(name); Ok(syn::parse_quote! { #ident }) } TypeKind::ObjCSel => Ok(syn::parse_quote! { objc::runtime::Sel }), TypeKind::ObjCId => Ok(syn::parse_quote! { id }), TypeKind::ObjCInterface(ref interface) => { let name = ctx.rust_ident(interface.name()); Ok(syn::parse_quote! { #name }) } ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) } } } } impl TryToOpaque for TemplateInstantiation { type Extra = Item; fn try_get_layout( &self, ctx: &BindgenContext, item: &Item, ) -> error::Result { item.expect_type() .layout(ctx) .ok_or(error::Error::NoLayoutForOpaqueBlob) } } impl TryToRustTy for TemplateInstantiation { type Extra = Item; fn try_to_rust_ty( &self, ctx: &BindgenContext, item: &Item, ) -> error::Result { if self.is_opaque(ctx, item) { return Err(error::Error::InstantiationOfOpaqueType); } let def = self .template_definition() .into_resolver() .through_type_refs() .resolve(ctx); let mut ty = quote! {}; let def_path = def.namespace_aware_canonical_path(ctx); ty.append_separated( def_path.into_iter().map(|p| ctx.rust_ident(p)), quote!(::), ); let def_params = def.self_template_params(ctx); if def_params.is_empty() { // This can happen if we generated an opaque type for a partial // template specialization, and we've hit an instantiation of // that partial specialization. extra_assert!(def.is_opaque(ctx, &())); return Err(error::Error::InstantiationOfOpaqueType); } // TODO: If the definition type is a template class/struct // definition's member template definition, it could rely on // generic template parameters from its outer template // class/struct. When we emit bindings for it, it could require // *more* type arguments than we have here, and we will need to // reconstruct them somehow. We don't have any means of doing // that reconstruction at this time. let template_args = self .template_arguments() .iter() .zip(def_params.iter()) // Only pass type arguments for the type parameters that // the def uses. .filter(|&(_, param)| ctx.uses_template_parameter(def.id(), *param)) .map(|(arg, _)| { let arg = arg.into_resolver().through_type_refs().resolve(ctx); let ty = arg .try_to_rust_ty(ctx, &())? .with_implicit_template_params(ctx, arg); Ok(ty) }) .collect::>>()?; Ok(if template_args.is_empty() { syn::parse_quote! { #ty } } else { syn::parse_quote! { #ty<#(#template_args),*> } }) } } impl TryToRustTy for FunctionSig { type Extra = Item; fn try_to_rust_ty( &self, ctx: &BindgenContext, item: &Item, ) -> error::Result { // 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); match self.abi(ctx, None) { Ok(abi) => Ok( syn::parse_quote! { unsafe extern #abi fn ( #( #arguments ),* ) #ret }, ), Err(err) => { if matches!(err, error::Error::UnsupportedAbi(_)) { unsupported_abi_diagnostic( self.name(), self.is_variadic(), item.location(), ctx, &err, ); } Err(err) } } } } impl CodeGenerator for Function { type Extra = Item; /// If we've actually generated the symbol, the number of times we've seen /// it. type Return = Option; fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) -> Self::Return { debug!("::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); let is_internal = matches!(self.linkage(), Linkage::Internal); 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), }; if is_internal { if !ctx.options().wrap_static_fns { // We cannot do anything with internal functions if we are not wrapping them so // just avoid generating anything for them. return None; } if signature.is_variadic() { // We cannot generate wrappers for variadic static functions so we avoid // generating any code for them. variadic_fn_diagnostic(self.name(), item.location(), ctx); return None; } } // Pure virtual methods have no actual symbol, so we can't generate // something meaningful for them. let is_dynamic_function = match self.kind() { FunctionKind::Method(ref method_kind) if method_kind.is_pure_virtual() => { return None; } FunctionKind::Function => { ctx.options().dynamic_library_name.is_some() } _ => false, }; // Similar to static member variables in a class template, we can't // generate bindings to template functions, because the set of // instantiations is open ended and we have no way of knowing which // monomorphizations actually exist. if !item.all_template_params(ctx).is_empty() { return None; } 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 None; } result.saw_function(seen_symbol_name); } let mut attributes = vec![]; if ctx.options().rust_features().must_use_function { let must_use = signature.must_use() || { let ret_ty = signature .return_type() .into_resolver() .through_type_refs() .resolve(ctx); ret_ty.must_use(ctx) }; if must_use { attributes.push(attributes::must_use()); } } if let Some(comment) = item.comment(ctx) { attributes.push(attributes::doc(comment)); } let abi = match signature.abi(ctx, Some(name)) { Err(err) => { if matches!(err, error::Error::UnsupportedAbi(_)) { unsupported_abi_diagnostic( name, signature.is_variadic(), item.location(), ctx, &err, ); } return None; } Ok(ClangAbi::Unknown(unknown_abi)) => { panic!( "Invalid or unknown abi {:?} for function {:?} ({:?})", unknown_abi, canonical_name, self ); } Ok(abi) => abi, }; // 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 mut has_link_name_attr = false; if let Some(link_name) = self.link_name() { attributes.push(attributes::link_name::(link_name)); has_link_name_attr = true; } else { let link_name = mangled_name.unwrap_or(name); if !is_dynamic_function && !utils::names_will_be_identical_after_mangling( &canonical_name, link_name, Some(abi), ) { attributes.push(attributes::link_name::(link_name)); has_link_name_attr = true; } } // Unfortunately this can't piggyback on the `attributes` list because // the #[link(wasm_import_module)] needs to happen before the `extern // "C"` block. It doesn't get picked up properly otherwise let wasm_link_attribute = ctx.options().wasm_import_module_name.as_ref().map(|name| { quote! { #[link(wasm_import_module = #name)] } }); let should_wrap = is_internal && ctx.options().wrap_static_fns && !has_link_name_attr; if should_wrap { let name = canonical_name.clone() + ctx.wrap_static_fns_suffix(); attributes.push(attributes::link_name::(&name)); } let wrap_as_variadic = if should_wrap && !signature.is_variadic() { utils::wrap_as_variadic_fn(ctx, signature, name) } else { None }; let (ident, args) = if let Some(WrapAsVariadic { idx_of_va_list_arg, new_name, }) = &wrap_as_variadic { ( new_name, utils::fnsig_arguments_iter( ctx, // Prune argument at index (idx_of_va_list_arg) signature.argument_types().iter().enumerate().filter_map( |(idx, t)| { if idx == *idx_of_va_list_arg { None } else { Some(t) } }, ), // and replace it by a `...` (variadic symbol and the end of the signature) true, ), ) } else { (&canonical_name, utils::fnsig_arguments(ctx, signature)) }; let ret = utils::fnsig_return_ty(ctx, signature); let ident = ctx.rust_ident(ident); let tokens = quote! { #wasm_link_attribute extern #abi { #(#attributes)* pub fn #ident ( #( #args ),* ) #ret; } }; // Add the item to the serialization list if necessary if should_wrap { result .items_to_serialize .push((item.id(), wrap_as_variadic)); } // If we're doing dynamic binding generation, add to the dynamic items. if is_dynamic_function { let args_identifiers = utils::fnsig_argument_identifiers(ctx, signature); let ret_ty = utils::fnsig_return_ty(ctx, signature); result.dynamic_items().push( ident, abi, signature.is_variadic(), ctx.options().dynamic_link_require_all, args, args_identifiers, ret, ret_ty, attributes, ctx, ); } else { result.push(tokens); } Some(times_seen) } } #[cfg_attr(not(feature = "experimental"), allow(unused_variables))] fn unsupported_abi_diagnostic( fn_name: &str, variadic: bool, location: Option<&crate::clang::SourceLocation>, ctx: &BindgenContext, error: &error::Error, ) { warn!( "Skipping {}function `{}` because the {}", if variadic { "variadic " } else { "" }, fn_name, error ); #[cfg(feature = "experimental")] if ctx.options().emit_diagnostics { use crate::diagnostics::{get_line, Diagnostic, Level, Slice}; let mut diag = Diagnostic::default(); diag.with_title( format!( "Skipping {}function `{}` because the {}", if variadic { "variadic " } else { "" }, fn_name, error ), Level::Warn, ) .add_annotation( "No code will be generated for this function.", Level::Warn, ) .add_annotation( format!( "The configured Rust version is {}.", ctx.options().rust_target ), Level::Note, ); if let Some(loc) = location { let (file, line, col, _) = loc.location(); if let Some(filename) = file.name() { if let Ok(Some(source)) = get_line(&filename, line) { let mut slice = Slice::default(); slice .with_source(source) .with_location(filename, line, col); diag.add_slice(slice); } } } diag.display() } } fn variadic_fn_diagnostic( fn_name: &str, _location: Option<&crate::clang::SourceLocation>, _ctx: &BindgenContext, ) { warn!( "Cannot generate wrapper for the static variadic function `{}`.", fn_name, ); #[cfg(feature = "experimental")] if _ctx.options().emit_diagnostics { use crate::diagnostics::{get_line, Diagnostic, Level, Slice}; let mut diag = Diagnostic::default(); diag.with_title(format!("Cannot generate wrapper for the static function `{}`.", fn_name), Level::Warn) .add_annotation("The `--wrap-static-fns` feature does not support variadic functions.", Level::Note) .add_annotation("No code will be generated for this function.", Level::Note); if let Some(loc) = _location { let (file, line, col, _) = loc.location(); if let Some(filename) = file.name() { if let Ok(Some(source)) = get_line(&filename, line) { let mut slice = Slice::default(); slice .with_source(source) .with_location(filename, line, col); diag.add_slice(slice); } } } diag.display() } } fn objc_method_codegen( ctx: &BindgenContext, method: &ObjCMethod, methods: &mut Vec, class_name: Option<&str>, rust_class_name: &str, prefix: &str, ) { // This would ideally resolve the method into an Item, and use // Item::process_before_codegen; however, ObjC methods are not currently // made into function items. let name = format!("{}::{}{}", rust_class_name, prefix, method.rust_name()); if ctx.options().blocklisted_items.matches(name) { return; } let signature = method.signature(); let fn_args = utils::fnsig_arguments(ctx, signature); let fn_ret = utils::fnsig_return_ty(ctx, signature); let sig = if method.is_class_method() { quote! { ( #( #fn_args ),* ) #fn_ret } } else { let self_arr = [quote! { &self }]; let args = self_arr.iter().chain(fn_args.iter()); quote! { ( #( #args ),* ) #fn_ret } }; let methods_and_args = method.format_method_call(&fn_args); let body = { let body = if method.is_class_method() { let class_name = ctx.rust_ident( class_name .expect("Generating a class method without class name?"), ); quote!(msg_send!(class!(#class_name), #methods_and_args)) } else { quote!(msg_send!(*self, #methods_and_args)) }; ctx.wrap_unsafe_ops(body) }; let method_name = ctx.rust_ident(format!("{}{}", prefix, method.rust_name())); methods.push(quote! { unsafe fn #method_name #sig where ::Target: objc::Message + Sized { #body } }); } impl CodeGenerator for ObjCInterface { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug_assert!(item.is_enabled_for_codegen(ctx)); let mut impl_items = vec![]; let rust_class_name = item.path_for_allowlisting(ctx)[1..].join("::"); for method in self.methods() { objc_method_codegen( ctx, method, &mut impl_items, None, &rust_class_name, "", ); } for class_method in self.class_methods() { let ambiquity = self .methods() .iter() .map(|m| m.rust_name()) .any(|x| x == class_method.rust_name()); let prefix = if ambiquity { "class_" } else { "" }; objc_method_codegen( ctx, class_method, &mut impl_items, Some(self.name()), &rust_class_name, prefix, ); } let trait_name = ctx.rust_ident(self.rust_name()); let trait_constraints = quote! { Sized + std::ops::Deref }; let trait_block = if self.is_template() { let template_names: Vec = self .template_names .iter() .map(|g| ctx.rust_ident(g)) .collect(); quote! { pub trait #trait_name <#(#template_names:'static),*> : #trait_constraints { #( #impl_items )* } } } else { quote! { pub trait #trait_name : #trait_constraints { #( #impl_items )* } } }; let class_name = ctx.rust_ident(self.name()); if !self.is_category() && !self.is_protocol() { let struct_block = quote! { #[repr(transparent)] #[derive(Debug, Copy, Clone)] pub struct #class_name(pub id); impl std::ops::Deref for #class_name { type Target = objc::runtime::Object; fn deref(&self) -> &Self::Target { unsafe { &*self.0 } } } unsafe impl objc::Message for #class_name { } impl #class_name { pub fn alloc() -> Self { Self(unsafe { msg_send!(class!(#class_name), alloc) }) } } }; result.push(struct_block); let mut protocol_set: HashSet = Default::default(); for protocol_id in self.conforms_to.iter() { protocol_set.insert(*protocol_id); let protocol_name = ctx.rust_ident( ctx.resolve_type(protocol_id.expect_type_id(ctx)) .name() .unwrap(), ); let impl_trait = quote! { impl #protocol_name for #class_name { } }; result.push(impl_trait); } let mut parent_class = self.parent_class; while let Some(parent_id) = parent_class { let parent = parent_id .expect_type_id(ctx) .into_resolver() .through_type_refs() .resolve(ctx) .expect_type() .kind(); let parent = match parent { TypeKind::ObjCInterface(ref parent) => parent, _ => break, }; parent_class = parent.parent_class; let parent_name = ctx.rust_ident(parent.rust_name()); let impl_trait = if parent.is_template() { let template_names: Vec = parent .template_names .iter() .map(|g| ctx.rust_ident(g)) .collect(); quote! { impl <#(#template_names :'static),*> #parent_name <#(#template_names),*> for #class_name { } } } else { quote! { impl #parent_name for #class_name { } } }; result.push(impl_trait); for protocol_id in parent.conforms_to.iter() { if protocol_set.insert(*protocol_id) { let protocol_name = ctx.rust_ident( ctx.resolve_type(protocol_id.expect_type_id(ctx)) .name() .unwrap(), ); let impl_trait = quote! { impl #protocol_name for #class_name { } }; result.push(impl_trait); } } if !parent.is_template() { let parent_struct_name = parent.name(); let child_struct_name = self.name(); let parent_struct = ctx.rust_ident(parent_struct_name); let from_block = quote! { impl From<#class_name> for #parent_struct { fn from(child: #class_name) -> #parent_struct { #parent_struct(child.0) } } }; result.push(from_block); let error_msg = format!( "This {} cannot be downcasted to {}", parent_struct_name, child_struct_name ); let try_into_block = quote! { impl std::convert::TryFrom<#parent_struct> for #class_name { type Error = &'static str; fn try_from(parent: #parent_struct) -> Result<#class_name, Self::Error> { let is_kind_of : bool = unsafe { msg_send!(parent, isKindOfClass:class!(#class_name))}; if is_kind_of { Ok(#class_name(parent.0)) } else { Err(#error_msg) } } } }; result.push(try_into_block); } } } if !self.is_protocol() { let impl_block = if self.is_template() { let template_names: Vec = self .template_names .iter() .map(|g| ctx.rust_ident(g)) .collect(); quote! { impl <#(#template_names :'static),*> #trait_name <#(#template_names),*> for #class_name { } } } else { quote! { impl #trait_name for #class_name { } } }; result.push(impl_block); } result.push(trait_block); result.saw_objc(); } } pub(crate) fn codegen( context: BindgenContext, ) -> Result<(proc_macro2::TokenStream, BindgenOptions), CodegenError> { context.gen(|context| { let _t = context.timer("codegen"); let counter = Cell::new(0); let mut result = CodegenResult::new(&counter); debug!("codegen: {:?}", context.options()); if context.options().emit_ir { let codegen_items = context.codegen_items(); for (id, item) in context.items() { if codegen_items.contains(&id) { println!("ir: {:?} = {:#?}", id, item); } } } if let Some(path) = context.options().emit_ir_graphviz.as_ref() { match dot::write_dot_file(context, path) { Ok(()) => info!( "Your dot file was generated successfully into: {}", path ), Err(e) => warn!("{}", e), } } if let Some(spec) = context.options().depfile.as_ref() { match spec.write(context.deps()) { Ok(()) => info!( "Your depfile was generated successfully into: {}", spec.depfile_path.display() ), Err(e) => warn!("{}", e), } } context.resolve_item(context.root_module()).codegen( context, &mut result, &(), ); if let Some(ref lib_name) = context.options().dynamic_library_name { let lib_ident = context.rust_ident(lib_name); let dynamic_items_tokens = result.dynamic_items().get_tokens(lib_ident, context); result.push(dynamic_items_tokens); } utils::serialize_items(&result, context)?; Ok(postprocessing::postprocessing( result.items, context.options(), )) }) } pub(crate) mod utils { use super::serialize::CSerialize; use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque}; use crate::ir::context::BindgenContext; use crate::ir::context::TypeId; use crate::ir::function::{Abi, ClangAbi, FunctionSig}; use crate::ir::item::{Item, ItemCanonicalPath}; use crate::ir::ty::TypeKind; use crate::{args_are_cpp, file_is_cpp}; use std::borrow::Cow; use std::io::Write; use std::mem; use std::path::PathBuf; use std::str::FromStr; pub(super) fn serialize_items( result: &CodegenResult, context: &BindgenContext, ) -> Result<(), CodegenError> { if result.items_to_serialize.is_empty() { return Ok(()); } let path = context .options() .wrap_static_fns_path .as_ref() .map(PathBuf::from) .unwrap_or_else(|| { std::env::temp_dir().join("bindgen").join("extern") }); let dir = path.parent().unwrap(); if !dir.exists() { std::fs::create_dir_all(dir)?; } let is_cpp = args_are_cpp(&context.options().clang_args) || context .options() .input_headers .iter() .any(|h| file_is_cpp(h)); let source_path = path.with_extension(if is_cpp { "cpp" } else { "c" }); let mut code = Vec::new(); if !context.options().input_headers.is_empty() { for header in &context.options().input_headers { writeln!(code, "#include \"{}\"", header)?; } writeln!(code)?; } if !context.options().input_header_contents.is_empty() { for (name, contents) in &context.options().input_header_contents { writeln!(code, "// {}\n{}", name, contents)?; } writeln!(code)?; } writeln!(code, "// Static wrappers\n")?; for (id, wrap_as_variadic) in &result.items_to_serialize { let item = context.resolve_item(*id); item.serialize(context, wrap_as_variadic, &mut vec![], &mut code)?; } std::fs::write(source_path, code)?; Ok(()) } pub(super) fn wrap_as_variadic_fn( ctx: &BindgenContext, signature: &FunctionSig, name: &str, ) -> Option { // Fast path, exclude because: // - with 0 args: no va_list possible, so no point searching for one // - with 1 args: cannot have a `va_list` and another arg (required by va_start) if signature.argument_types().len() <= 1 { return None; } let mut it = signature.argument_types().iter().enumerate().filter_map( |(idx, (_name, mut type_id))| { // Hand rolled visitor that checks for the presence of `va_list` loop { let ty = ctx.resolve_type(type_id); if Some("__builtin_va_list") == ty.name() { return Some(idx); } match ty.kind() { TypeKind::Alias(type_id_alias) => { type_id = *type_id_alias } TypeKind::ResolvedTypeRef(type_id_typedef) => { type_id = *type_id_typedef } _ => break, } } None }, ); // Return THE idx (by checking that there is no idx after) // This is done since we cannot handle multiple `va_list` it.next().filter(|_| it.next().is_none()).and_then(|idx| { // Call the `wrap_as_variadic_fn` callback #[cfg(feature = "experimental")] { ctx.options() .last_callback(|c| c.wrap_as_variadic_fn(name)) .map(|new_name| super::WrapAsVariadic { new_name, idx_of_va_list_arg: idx, }) } #[cfg(not(feature = "experimental"))] { let _ = name; let _ = idx; None } }) } pub(crate) fn prepend_bitfield_unit_type( ctx: &BindgenContext, result: &mut Vec, ) { let bitfield_unit_src = include_str!("./bitfield_unit.rs"); let bitfield_unit_src = if ctx.options().rust_features().min_const_fn { Cow::Borrowed(bitfield_unit_src) } else { Cow::Owned(bitfield_unit_src.replace("const fn ", "fn ")) }; let bitfield_unit_type = proc_macro2::TokenStream::from_str(&bitfield_unit_src).unwrap(); let bitfield_unit_type = quote!(#bitfield_unit_type); let items = vec![bitfield_unit_type]; let old_items = mem::replace(result, items); result.extend(old_items); } pub(crate) fn prepend_objc_header( ctx: &BindgenContext, result: &mut Vec, ) { let use_objc = if ctx.options().objc_extern_crate { quote! { #[macro_use] extern crate objc; } } else { quote! { use objc::{self, msg_send, sel, sel_impl, class}; } }; let id_type = quote! { #[allow(non_camel_case_types)] pub type id = *mut objc::runtime::Object; }; let items = vec![use_objc, id_type]; let old_items = mem::replace(result, items); result.extend(old_items); } pub(crate) fn prepend_block_header( ctx: &BindgenContext, result: &mut Vec, ) { let use_block = if ctx.options().block_extern_crate { quote! { extern crate block; } } else { quote! { use block; } }; let items = vec![use_block]; let old_items = mem::replace(result, items); result.extend(old_items); } pub(crate) fn prepend_union_types( ctx: &BindgenContext, result: &mut Vec, ) { let prefix = ctx.trait_prefix(); // If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. let const_fn = if ctx.options().rust_features().min_const_fn { quote! { const fn } } else { quote! { fn } }; // TODO(emilio): The fmt::Debug impl could be way nicer with // std::intrinsics::type_name, but... let union_field_decl = quote! { #[repr(C)] pub struct __BindgenUnionField(::#prefix::marker::PhantomData); }; let transmute = ctx.wrap_unsafe_ops(quote!(::#prefix::mem::transmute(self))); let union_field_impl = quote! { impl __BindgenUnionField { #[inline] pub #const_fn new() -> Self { __BindgenUnionField(::#prefix::marker::PhantomData) } #[inline] pub unsafe fn as_ref(&self) -> &T { #transmute } #[inline] pub unsafe fn as_mut(&mut self) -> &mut T { #transmute } } }; let union_field_default_impl = quote! { impl ::#prefix::default::Default for __BindgenUnionField { #[inline] fn default() -> Self { Self::new() } } }; let union_field_clone_impl = quote! { impl ::#prefix::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { *self } } }; let union_field_copy_impl = quote! { impl ::#prefix::marker::Copy for __BindgenUnionField {} }; let union_field_debug_impl = quote! { impl ::#prefix::fmt::Debug for __BindgenUnionField { fn fmt(&self, fmt: &mut ::#prefix::fmt::Formatter<'_>) -> ::#prefix::fmt::Result { fmt.write_str("__BindgenUnionField") } } }; // The actual memory of the filed will be hashed, so that's why these // field doesn't do anything with the hash. let union_field_hash_impl = quote! { impl ::#prefix::hash::Hash for __BindgenUnionField { fn hash(&self, _state: &mut H) { } } }; let union_field_partialeq_impl = quote! { impl ::#prefix::cmp::PartialEq for __BindgenUnionField { fn eq(&self, _other: &__BindgenUnionField) -> bool { true } } }; let union_field_eq_impl = quote! { impl ::#prefix::cmp::Eq for __BindgenUnionField { } }; 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, union_field_hash_impl, union_field_partialeq_impl, union_field_eq_impl, ]; let old_items = mem::replace(result, items); result.extend(old_items); } pub(crate) fn prepend_incomplete_array_types( ctx: &BindgenContext, result: &mut Vec, ) { let prefix = ctx.trait_prefix(); // If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. let const_fn = if ctx.options().rust_features().min_const_fn { quote! { const fn } } else { quote! { fn } }; let incomplete_array_decl = quote! { #[repr(C)] #[derive(Default)] pub struct __IncompleteArrayField( ::#prefix::marker::PhantomData, [T; 0]); }; let from_raw_parts = ctx.wrap_unsafe_ops(quote! ( ::#prefix::slice::from_raw_parts(self.as_ptr(), len) )); let from_raw_parts_mut = ctx.wrap_unsafe_ops(quote! ( ::#prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) )); let incomplete_array_impl = quote! { impl __IncompleteArrayField { #[inline] pub #const_fn new() -> Self { __IncompleteArrayField(::#prefix::marker::PhantomData, []) } #[inline] pub fn as_ptr(&self) -> *const T { self as *const _ as *const T } #[inline] pub fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut T } #[inline] pub unsafe fn as_slice(&self, len: usize) -> &[T] { #from_raw_parts } #[inline] pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { #from_raw_parts_mut } } }; let incomplete_array_debug_impl = quote! { impl ::#prefix::fmt::Debug for __IncompleteArrayField { fn fmt(&self, fmt: &mut ::#prefix::fmt::Formatter<'_>) -> ::#prefix::fmt::Result { fmt.write_str("__IncompleteArrayField") } } }; let items = vec![ incomplete_array_decl, incomplete_array_impl, incomplete_array_debug_impl, ]; let old_items = mem::replace(result, items); result.extend(old_items); } pub(crate) fn prepend_float16_type( result: &mut Vec, ) { let float16_type = quote! { #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[repr(transparent)] pub struct __BindgenFloat16(pub u16); }; let items = vec![float16_type]; let old_items = mem::replace(result, items); result.extend(old_items); } pub(crate) fn prepend_complex_type( result: &mut Vec, ) { let complex_type = quote! { #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[repr(C)] pub struct __BindgenComplex { pub re: T, pub im: T } }; let items = vec![complex_type]; let old_items = mem::replace(result, items); result.extend(old_items); } pub(crate) fn build_path( item: &Item, ctx: &BindgenContext, ) -> error::Result { let path = item.namespace_aware_canonical_path(ctx); let tokens = proc_macro2::TokenStream::from_str(&path.join("::")).unwrap(); Ok(syn::parse_quote! { #tokens }) } fn primitive_ty(ctx: &BindgenContext, name: &str) -> syn::Type { let ident = ctx.rust_ident_raw(name); syn::parse_quote! { #ident } } pub(crate) fn type_from_named( ctx: &BindgenContext, name: &str, ) -> 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"), "size_t" if ctx.options().size_t_is_usize => { primitive_ty(ctx, "usize") } "uintptr_t" => primitive_ty(ctx, "usize"), "ssize_t" if ctx.options().size_t_is_usize => { primitive_ty(ctx, "isize") } "intptr_t" | "ptrdiff_t" => primitive_ty(ctx, "isize"), _ => return None, }) } fn fnsig_return_ty_internal( ctx: &BindgenContext, sig: &FunctionSig, ) -> syn::Type { if sig.is_divergent() { return syn::parse_quote! { ! }; } let canonical_type_kind = sig .return_type() .into_resolver() .through_type_refs() .through_type_aliases() .resolve(ctx) .kind() .expect_type() .kind(); match canonical_type_kind { TypeKind::Void => syn::parse_quote! { () }, _ => sig.return_type().to_rust_ty_or_opaque(ctx, &()), } } pub(crate) fn fnsig_return_ty( ctx: &BindgenContext, sig: &FunctionSig, ) -> proc_macro2::TokenStream { match fnsig_return_ty_internal(ctx, sig) { syn::Type::Tuple(syn::TypeTuple { elems, .. }) if elems.is_empty() => { quote! {} } ty => quote! { -> #ty }, } } pub(crate) fn fnsig_argument_type( ctx: &BindgenContext, ty: &TypeId, ) -> syn::Type { use super::ToPtr; 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 match *arg_ty.canonical_type(ctx).kind() { TypeKind::Array(t, _) => { let stream = if ctx.options().array_pointers_in_arguments { arg_ty.to_rust_ty_or_opaque(ctx, arg_item) } else { t.to_rust_ty_or_opaque(ctx, &()) }; stream.to_ptr(ctx.resolve_type(t).is_const()) } TypeKind::Pointer(inner) => { let inner = ctx.resolve_item(inner); let inner_ty = inner.expect_type(); if let TypeKind::ObjCInterface(ref interface) = *inner_ty.canonical_type(ctx).kind() { let name = ctx.rust_ident(interface.name()); syn::parse_quote! { #name } } else { arg_item.to_rust_ty_or_opaque(ctx, &()) } } _ => arg_item.to_rust_ty_or_opaque(ctx, &()), } } pub(crate) fn fnsig_arguments_iter< 'a, I: Iterator, crate::ir::context::TypeId)>, >( ctx: &BindgenContext, args_iter: I, is_variadic: bool, ) -> Vec { let mut unnamed_arguments = 0; let mut args = args_iter .map(|(name, ty)| { let arg_ty = fnsig_argument_type(ctx, ty); 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()); let arg_name = ctx.rust_ident(arg_name); quote! { #arg_name : #arg_ty } }) .collect::>(); if is_variadic { args.push(quote! { ... }) } args } pub(crate) fn fnsig_arguments( ctx: &BindgenContext, sig: &FunctionSig, ) -> Vec { fnsig_arguments_iter( ctx, sig.argument_types().iter(), sig.is_variadic(), ) } pub(crate) fn fnsig_argument_identifiers( ctx: &BindgenContext, sig: &FunctionSig, ) -> Vec { let mut unnamed_arguments = 0; let args = sig .argument_types() .iter() .map(|&(ref name, _ty)| { 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()); let arg_name = ctx.rust_ident(arg_name); quote! { #arg_name } }) .collect::>(); args } pub(crate) fn fnsig_block( ctx: &BindgenContext, sig: &FunctionSig, ) -> proc_macro2::TokenStream { let args = sig.argument_types().iter().map(|&(_, ty)| { let arg_item = ctx.resolve_item(ty); arg_item.to_rust_ty_or_opaque(ctx, &()) }); let ret_ty = fnsig_return_ty_internal(ctx, sig); quote! { *const ::block::Block<(#(#args,)*), #ret_ty> } } // Returns true if `canonical_name` will end up as `mangled_name` at the // machine code level, i.e. after LLVM has applied any target specific // mangling. pub(crate) fn names_will_be_identical_after_mangling( canonical_name: &str, mangled_name: &str, call_conv: Option, ) -> bool { // If the mangled name and the canonical name are the same then no // mangling can have happened between the two versions. if canonical_name == mangled_name { return true; } // Working with &[u8] makes indexing simpler than with &str let canonical_name = canonical_name.as_bytes(); let mangled_name = mangled_name.as_bytes(); let (mangling_prefix, expect_suffix) = match call_conv { Some(ClangAbi::Known(Abi::C)) | // None is the case for global variables None => { (b'_', false) } Some(ClangAbi::Known(Abi::Stdcall)) => (b'_', true), Some(ClangAbi::Known(Abi::Fastcall)) => (b'@', true), // This is something we don't recognize, stay on the safe side // by emitting the `#[link_name]` attribute Some(_) => return false, }; // Check that the mangled name is long enough to at least contain the // canonical name plus the expected prefix. if mangled_name.len() < canonical_name.len() + 1 { return false; } // Return if the mangled name does not start with the prefix expected // for the given calling convention. if mangled_name[0] != mangling_prefix { return false; } // Check that the mangled name contains the canonical name after the // prefix if &mangled_name[1..canonical_name.len() + 1] != canonical_name { return false; } // If the given calling convention also prescribes a suffix, check that // it exists too if expect_suffix { let suffix = &mangled_name[canonical_name.len() + 1..]; // The shortest suffix is "@0" if suffix.len() < 2 { return false; } // Check that the suffix starts with '@' and is all ASCII decimals // after that. if suffix[0] != b'@' || !suffix[1..].iter().all(u8::is_ascii_digit) { return false; } } else if mangled_name.len() != canonical_name.len() + 1 { // If we don't expect a prefix but there is one, we need the // #[link_name] attribute return false; } true } }