| 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::{ | |
| AttributeInfo, DeriveInfo, DiscoveredItem, DiscoveredItemId, | |
| FieldAttributeInfo, 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::{Ident, Span}; | |
| use quote::{ToTokens, 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<std::io::Error> 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<proc_macro2::TokenStream> { | |
| 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(); | |
| if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() { | |
| derivable_traits |= DerivableTraits::COPY; | |
| // 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 | |
| } | |
| /// Appends the contents of the `custom_derives` slice to the `derives` vector, | |
| /// ignoring duplicates and preserving order. | |
| fn append_custom_derives<'a>( | |
| derives: &mut Vec<&'a str>, | |
| custom_derives: &'a [String], | |
| ) { | |
| for custom_derive in custom_derives.iter().map(|s| s.as_str()) { | |
| if !derives.contains(&custom_derive) { | |
| derives.push(custom_derive); | |
| } | |
| } | |
| } | |
| /// Collects field attributes from multiple sources (annotations, callbacks, and CLI/Builder patterns). | |
| fn collect_field_attributes( | |
| ctx: &BindgenContext, | |
| annotations: &Annotations, | |
| type_name: &str, | |
| type_kind: DeriveTypeKind, | |
| field_name: &str, | |
| field_type_name: Option<&str>, | |
| ) -> Vec<String> { | |
| let mut all_field_attributes = Vec::new(); | |
| // 1. Get attributes from annotations | |
| all_field_attributes.extend(annotations.attributes().iter().cloned()); | |
| // 2. Get custom attributes from callbacks | |
| all_field_attributes.extend(ctx.options().all_callbacks(|cb| { | |
| cb.field_attributes(&FieldAttributeInfo { | |
| type_name, | |
| type_kind, | |
| field_name, | |
| field_type_name, | |
| }) | |
| })); | |
| // 3. Get attributes from CLI/Builder patterns | |
| for (type_pat, field_pat, attr) in &ctx.options().field_attr_patterns { | |
| if type_pat.as_ref() == type_name && field_pat.as_ref() == field_name { | |
| all_field_attributes.push(attr.to_string()); | |
| } | |
| } | |
| all_field_attributes | |
| } | |
| impl From<DerivableTraits> 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)| { | |
| derivable_traits.contains(flag).then_some(derive) | |
| }) | |
| .collect() | |
| } | |
| } | |
| struct WrapAsVariadic { | |
| new_name: String, | |
| idx_of_va_list_arg: usize, | |
| } | |
| struct CodegenResult<'a> { | |
| items: Vec<proc_macro2::TokenStream>, | |
| 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<usize>, | |
| /// 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<ItemId>, | |
| /// The set of generated function/var names, needed because in C/C++ is | |
| /// legal to do something like: | |
| /// | |
| /// ```c++ | |
| /// extern "C" { | |
| /// void foo(); | |
| /// extern int bar; | |
| /// } | |
| /// | |
| /// extern "C" { | |
| /// void foo(); | |
| /// extern int bar; | |
| /// } | |
| /// ``` | |
| /// | |
| /// Being these two different declarations. | |
| functions_seen: HashSet<String>, | |
| vars_seen: HashSet<String>, | |
| /// Used for making bindings to overloaded functions. Maps from a canonical | |
| /// function name to the number of overloads we have already codegen'd for | |
| /// that name. This lets us give each overload a unique suffix. | |
| overload_counters: HashMap<String, u32>, | |
| /// List of items to serialize. With optionally the argument for the wrap as | |
| /// variadic transformation to be applied. | |
| items_to_serialize: Vec<(ItemId, Option<WrapAsVariadic>)>, | |
| } | |
| impl<'a> CodegenResult<'a> { | |
| fn new(codegen_id: &'a Cell<usize>) -> 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<Id: Into<ItemId>>(&self, item: Id) -> bool { | |
| self.items_seen.contains(&item.into()) | |
| } | |
| fn set_seen<Id: Into<ItemId>>(&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<F>(&mut self, cb: F) -> Vec<proc_macro2::TokenStream> | |
| 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 ops::Deref for CodegenResult<'_> { | |
| type Target = Vec<proc_macro2::TokenStream>; | |
| fn deref(&self) -> &Self::Target { | |
| &self.items | |
| } | |
| } | |
| impl ops::DerefMut for CodegenResult<'_> { | |
| 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!( | |
| "<Item as CodeGenerator>::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!("<Item as CodeGenerator>::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!("<Module as CodeGenerator>::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); | |
| } | |
| utils::prepend_opaque_array_types(ctx, &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!("<Var as CodeGenerator>::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() { | |
| utils::call_discovered_item_callback(ctx, item, || { | |
| DiscoveredItem::Constant { | |
| final_name: canonical_name.clone(), | |
| } | |
| }); | |
| let const_expr = match *val { | |
| VarType::Bool(val) => Some(val.to_token_stream()), | |
| 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 _) | |
| }; | |
| Some(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(), | |
| ); | |
| let cstr = | |
| if options.generate_cstr && rust_features.const_cstr { | |
| CStr::from_bytes_with_nul(&cstr_bytes).ok() | |
| } else { | |
| None | |
| }; | |
| if let Some(cstr) = cstr { | |
| let cstr_ty = quote! { ::#prefix::ffi::CStr }; | |
| if rust_features.literal_cstr { | |
| let cstr = proc_macro2::Literal::c_string(cstr); | |
| result.push(quote! { | |
| #(#attrs)* | |
| pub const #canonical_ident: &#cstr_ty = #cstr; | |
| }); | |
| } else { | |
| let bytes = | |
| proc_macro2::Literal::byte_string(&cstr_bytes); | |
| result.push(quote! { | |
| #(#attrs)* | |
| #[allow(unsafe_code)] | |
| pub const #canonical_ident: &#cstr_ty = unsafe { | |
| #cstr_ty::from_bytes_with_nul_unchecked(#bytes) | |
| }; | |
| }); | |
| } | |
| } else { | |
| // 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 bytes = | |
| proc_macro2::Literal::byte_string(&cstr_bytes); | |
| let lifetime = | |
| if true { None } else { Some(quote! { 'static }) } | |
| .into_iter(); | |
| result.push(quote! { | |
| #(#attrs)* | |
| pub const #canonical_ident: &#(#lifetime )*#array_ty = #bytes ; | |
| }); | |
| } | |
| None | |
| } | |
| VarType::Float(f) => helpers::ast_ty::float_expr(f).ok(), | |
| VarType::Char(c) => Some(c.to_token_stream()), | |
| }; | |
| if let Some(mut val) = const_expr { | |
| let var_ty_item = | |
| var_ty.into_resolver().through_type_refs().resolve(ctx); | |
| let is_alias = var_ty_item | |
| .as_type() | |
| .is_some_and(|ty| matches!(ty.kind(), TypeKind::Alias(..))); | |
| if is_alias && | |
| matches!( | |
| var_ty_item.alias_style(ctx), | |
| AliasVariation::NewType | AliasVariation::NewTypeDeref | |
| ) | |
| { | |
| val = quote! { #ty(#val) }; | |
| } | |
| result.push(quote! { | |
| #(#attrs)* | |
| pub const #canonical_ident : #ty = #val ; | |
| }); | |
| } | |
| } else { | |
| utils::call_discovered_item_callback(ctx, item, || { | |
| DiscoveredItem::Variable { | |
| final_name: canonical_name.clone(), | |
| } | |
| }); | |
| let symbol: &str = self.link_name().unwrap_or_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, | |
| ) { | |
| canonical_name.as_str() | |
| } else { | |
| attrs.push(attributes::link_name::<false>(link_name)); | |
| link_name | |
| } | |
| }); | |
| let mut block_attributes = quote! {}; | |
| for attr in &ctx.options().extern_block_attrs { | |
| let parsed_attr = proc_macro2::TokenStream::from_str(attr).unwrap_or_else( | |
| |err| { | |
| panic!( | |
| "Error parsing extern static block attribute `{attr}`: {err}" | |
| ) | |
| }, | |
| ); | |
| block_attributes.extend(quote! { | |
| #parsed_attr | |
| }); | |
| } | |
| let maybe_mut = if self.is_const() { | |
| quote! {} | |
| } else { | |
| quote! { mut } | |
| }; | |
| let safety = ctx | |
| .options() | |
| .rust_features | |
| .unsafe_extern_blocks | |
| .then(|| quote!(unsafe)); | |
| let tokens = quote!( | |
| #block_attributes | |
| #safety extern "C" { | |
| #(#attrs)* | |
| pub static #maybe_mut #canonical_ident: #ty; | |
| } | |
| ); | |
| if ctx.options().dynamic_library_name.is_some() { | |
| result.dynamic_items().push_var( | |
| &canonical_ident, | |
| symbol, | |
| &self | |
| .ty() | |
| .to_rust_ty_or_opaque(ctx, &()) | |
| .into_token_stream(), | |
| ctx.options().dynamic_link_require_all, | |
| ctx.options().wrap_unsafe_ops, | |
| ); | |
| } else { | |
| result.push(tokens); | |
| } | |
| } | |
| } | |
| } | |
| impl CodeGenerator for Type { | |
| type Extra = Item; | |
| type Return = (); | |
| fn codegen( | |
| &self, | |
| ctx: &BindgenContext, | |
| result: &mut CodegenResult<'_>, | |
| item: &Item, | |
| ) { | |
| debug!("<Type as CodeGenerator>::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 `{spelling}` ({}) does not match the target pointer size ({})", | |
| layout.size, | |
| 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); | |
| utils::call_discovered_item_callback(ctx, item, || { | |
| DiscoveredItem::Alias { | |
| alias_name: rust_name.to_string(), | |
| alias_for: DiscoveredItemId::new( | |
| inner_item.id().as_usize(), | |
| ), | |
| } | |
| }); | |
| let mut tokens = if let Some(comment) = item.comment(ctx) { | |
| attributes::doc(&comment) | |
| } else { | |
| quote! {} | |
| }; | |
| let alias_style = item.alias_style(ctx); | |
| let mut needs_debug_impl = false; | |
| // 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 => { | |
| 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.contains(DerivableTraits::DEBUG) { | |
| needs_debug_impl = ctx.options().derive_debug && | |
| ctx.options().impl_debug && | |
| !ctx.no_debug_by_name(item) && | |
| !item.annotations().disallow_debug(); | |
| } | |
| let mut derives: Vec<_> = derivable_traits.into(); | |
| // 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::Struct, | |
| }) | |
| }); | |
| // In most cases this will be a no-op, since custom_derives will be empty. | |
| append_custom_derives(&mut derives, &custom_derives); | |
| attributes.push(attributes::derives(&derives)); | |
| let custom_attributes = | |
| ctx.options().all_callbacks(|cb| { | |
| cb.add_attributes(&AttributeInfo { | |
| name: &name, | |
| kind: DeriveTypeKind::Struct, | |
| }) | |
| }); | |
| attributes.extend( | |
| custom_attributes | |
| .iter() | |
| .map(|s| s.parse().unwrap()), | |
| ); | |
| 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 ),* > | |
| }); | |
| } | |
| tokens.append_all(match alias_style { | |
| AliasVariation::TypeAlias => quote! { | |
| = #inner_rust_type ; | |
| }, | |
| AliasVariation::NewType | AliasVariation::NewTypeDeref => { | |
| let visibility = ctx | |
| .options() | |
| .last_callback(|cb| { | |
| cb.field_visibility(FieldInfo { | |
| type_name: &item.canonical_name(ctx), | |
| field_name: "0", | |
| field_type_name: inner_item | |
| .expect_type() | |
| .name(), | |
| }) | |
| }) | |
| .unwrap_or(ctx.options().default_visibility); | |
| let access_spec = access_specifier(visibility); | |
| // Collect field attributes for newtype tuple field | |
| let type_name = item.canonical_name(ctx); | |
| let all_field_attributes = collect_field_attributes( | |
| ctx, | |
| item.annotations(), | |
| &type_name, | |
| DeriveTypeKind::Struct, | |
| "0", | |
| inner_item.expect_type().name(), | |
| ); | |
| // Build the field with attributes | |
| let mut field_tokens = quote! {}; | |
| for attr in &all_field_attributes { | |
| let attr_tokens: proc_macro2::TokenStream = | |
| attr.parse().expect("Invalid field attribute"); | |
| field_tokens.append_all(quote! { | |
| #[#attr_tokens] | |
| }); | |
| } | |
| field_tokens.append_all(quote! { | |
| #access_spec #inner_rust_type | |
| }); | |
| quote! { | |
| (#field_tokens) ; | |
| } | |
| } | |
| }); | |
| 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 | |
| } | |
| } | |
| }); | |
| } | |
| if needs_debug_impl { | |
| let prefix = ctx.trait_prefix(); | |
| tokens.append_all(quote! { | |
| impl ::#prefix::fmt::Debug for #rust_name { | |
| fn fmt(&self, f: &mut ::#prefix::fmt::Formatter<'_>) -> ::#prefix::fmt::Result { | |
| f.debug_tuple(stringify!(#rust_name)).field(&self.0).finish() | |
| } | |
| } | |
| }); | |
| } | |
| 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 CodeGenerator for Vtable<'_> { | |
| 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 TypeKind::Function(ref signature) = signature_item.expect_type().kind() else { 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::<Vec<_>>(); | |
| 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 ItemCanonicalName for Vtable<'_> { | |
| fn canonical_name(&self, ctx: &BindgenContext) -> String { | |
| format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) | |
| } | |
| } | |
| impl TryToRustTy for Vtable<'_> { | |
| type Extra = (); | |
| fn try_to_rust_ty( | |
| &self, | |
| ctx: &BindgenContext, | |
| _: &(), | |
| ) -> error::Result<syn::Type> { | |
| 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; | |
| } | |
| // For consistency with other layout tests, gate this on offset_of. | |
| let compile_time = ctx.options().rust_features().offset_of; | |
| // 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 fn_name = if compile_time { | |
| None | |
| } else { | |
| let mut fn_name = | |
| format!("__bindgen_test_layout_{name}_instantiation"); | |
| let times_seen = result.overload_number(&fn_name); | |
| if times_seen > 0 { | |
| write!(&mut fn_name, "_{times_seen}").unwrap(); | |
| } | |
| Some(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 size_of_err = | |
| format!("Size of template specialization: {name}"); | |
| let align_of_err = | |
| format!("Align of template specialization: {name}"); | |
| if compile_time { | |
| // In an ideal world this would be assert_eq!, but that is not | |
| // supported in const fn due to the need for string formatting. | |
| // If #size_of_expr > #size, this will index OOB, and if | |
| // #size_of_expr < #size, the subtraction will overflow, both | |
| // of which print enough information to see what has gone wrong. | |
| result.push(quote! { | |
| #[allow(clippy::unnecessary_operation, clippy::identity_op)] | |
| const _: () = { | |
| [#size_of_err][#size_of_expr - #size]; | |
| [#align_of_err][#align_of_expr - #align]; | |
| }; | |
| }); | |
| } else { | |
| result.push(quote! { | |
| #[test] | |
| fn #fn_name() { | |
| assert_eq!(#size_of_expr, #size, #size_of_err); | |
| assert_eq!(#align_of_expr, #align, #align_of_err); | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| } | |
| /// Trait for implementing the code generation of a struct or union field. | |
| trait FieldCodegen<'a> { | |
| type Extra; | |
| #[allow(clippy::too_many_arguments)] | |
| fn codegen<F, M>( | |
| &self, | |
| ctx: &BindgenContext, | |
| visibility_kind: FieldVisibilityKind, | |
| accessor_kind: FieldAccessorKind, | |
| parent: &CompInfo, | |
| parent_item: &Item, | |
| last_field: bool, | |
| result: &mut CodegenResult, | |
| struct_layout: &mut StructLayoutTracker, | |
| fields: &mut F, | |
| methods: &mut M, | |
| extra: Self::Extra, | |
| ) where | |
| F: Extend<proc_macro2::TokenStream>, | |
| M: Extend<proc_macro2::TokenStream>; | |
| } | |
| impl FieldCodegen<'_> for Field { | |
| type Extra = (); | |
| fn codegen<F, M>( | |
| &self, | |
| ctx: &BindgenContext, | |
| visibility_kind: FieldVisibilityKind, | |
| accessor_kind: FieldAccessorKind, | |
| parent: &CompInfo, | |
| parent_item: &Item, | |
| last_field: bool, | |
| result: &mut CodegenResult, | |
| struct_layout: &mut StructLayoutTracker, | |
| fields: &mut F, | |
| methods: &mut M, | |
| _: (), | |
| ) where | |
| F: Extend<proc_macro2::TokenStream>, | |
| M: Extend<proc_macro2::TokenStream>, | |
| { | |
| match *self { | |
| Field::DataMember(ref data) => { | |
| data.codegen( | |
| ctx, | |
| visibility_kind, | |
| accessor_kind, | |
| parent, | |
| parent_item, | |
| last_field, | |
| result, | |
| struct_layout, | |
| fields, | |
| methods, | |
| (), | |
| ); | |
| } | |
| Field::Bitfields(ref unit) => { | |
| unit.codegen( | |
| ctx, | |
| visibility_kind, | |
| accessor_kind, | |
| parent, | |
| parent_item, | |
| last_field, | |
| 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 FieldCodegen<'_> for FieldData { | |
| type Extra = (); | |
| fn codegen<F, M>( | |
| &self, | |
| ctx: &BindgenContext, | |
| parent_visibility_kind: FieldVisibilityKind, | |
| accessor_kind: FieldAccessorKind, | |
| parent: &CompInfo, | |
| parent_item: &Item, | |
| last_field: bool, | |
| result: &mut CodegenResult, | |
| struct_layout: &mut StructLayoutTracker, | |
| fields: &mut F, | |
| methods: &mut M, | |
| _: (), | |
| ) where | |
| F: Extend<proc_macro2::TokenStream>, | |
| M: Extend<proc_macro2::TokenStream>, | |
| { | |
| // 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) { | |
| // Only FAM if its the last field | |
| if ctx.options().flexarray_dst && last_field { | |
| // Check if parent struct is packed to determine if we need ManuallyDrop | |
| let layout = parent_item.expect_type().layout(ctx); | |
| let is_packed = parent.is_packed(ctx, layout.as_ref()); | |
| struct_layout.saw_flexible_array(); | |
| // For packed structs, we need to wrap FAM in ManuallyDrop | |
| // because Rust requires that DST fields in packed structs | |
| // don't need Drop to be run. | |
| if is_packed { | |
| let prefix = ctx.trait_prefix(); | |
| syn::parse_quote! { ::#prefix::mem::ManuallyDrop<FAM> } | |
| } else { | |
| syn::parse_quote! { FAM } | |
| } | |
| } else { | |
| 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 if let TypeKind::Comp(ref comp) = field_ty.kind() { | |
| // Nested FAM: the field is a struct that itself has a FAM | |
| // Only treat as FAM if it's the last field | |
| if ctx.options().flexarray_dst && | |
| last_field && | |
| comp.flex_array_member(ctx).is_some() | |
| { | |
| let layout = parent_item.expect_type().layout(ctx); | |
| let is_packed = parent.is_packed(ctx, layout.as_ref()); | |
| struct_layout.saw_flexible_array(); | |
| // For nested FAMs, we need to parameterize the field type with FAM | |
| // For packed structs, wrap in ManuallyDrop | |
| if is_packed { | |
| let prefix = ctx.trait_prefix(); | |
| syn::parse_quote! { ::#prefix::mem::ManuallyDrop<#ty<FAM>> } | |
| } else { | |
| syn::parse_quote! { #ty<FAM> } | |
| } | |
| } else { | |
| ty | |
| } | |
| } else { | |
| ty | |
| }; | |
| let mut field = quote! {}; | |
| if let Some(comment) = self.doc_comment(ctx) { | |
| 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, | |
| field_type_name: field_ty.name(), | |
| }) | |
| }), | |
| self.annotations(), | |
| parent_visibility_kind, | |
| ); | |
| let accessor_kind = | |
| self.annotations().accessor_kind().unwrap_or(accessor_kind); | |
| // Collect field attributes from multiple sources | |
| let type_name = parent_item.canonical_name(ctx); | |
| let type_kind = if parent.is_union() { | |
| DeriveTypeKind::Union | |
| } else { | |
| DeriveTypeKind::Struct | |
| }; | |
| let all_field_attributes = collect_field_attributes( | |
| ctx, | |
| self.annotations(), | |
| &type_name, | |
| type_kind, | |
| field_name, | |
| field_ty.name(), | |
| ); | |
| // Apply all custom attributes to the field | |
| for attr in &all_field_attributes { | |
| let attr_tokens: proc_macro2::TokenStream = | |
| attr.parse().expect("Invalid field attribute"); | |
| field.append_all(quote! { | |
| #[#attr_tokens] | |
| }); | |
| } | |
| 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_{field_name}_mut")); | |
| 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(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; | |
| ctor_impl.append_all(quote! { | |
| __bindgen_bitfield_unit.set_const::<#offset, #width>( | |
| { | |
| let #param_name: #bitfield_int_ty = #param_name as _; | |
| #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<FieldVisibilityKind>, | |
| 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 FieldCodegen<'_> for BitfieldUnit { | |
| type Extra = (); | |
| fn codegen<F, M>( | |
| &self, | |
| ctx: &BindgenContext, | |
| visibility_kind: FieldVisibilityKind, | |
| accessor_kind: FieldAccessorKind, | |
| parent: &CompInfo, | |
| parent_item: &Item, | |
| last_field: bool, | |
| result: &mut CodegenResult, | |
| struct_layout: &mut StructLayoutTracker, | |
| fields: &mut F, | |
| methods: &mut M, | |
| _: (), | |
| ) where | |
| F: Extend<proc_macro2::TokenStream>, | |
| M: Extend<proc_macro2::TokenStream>, | |
| { | |
| 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 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; | |
| let bfields = self.bitfields(); | |
| for (idx, bf) in bfields.iter().enumerate() { | |
| // Codegen not allowed for anonymous bitfields | |
| if bf.name().is_none() { | |
| continue; | |
| } | |
| let mut bitfield_representable_as_int = true; | |
| let mut bitfield_visibility = visibility_kind; | |
| bf.codegen( | |
| ctx, | |
| visibility_kind, | |
| accessor_kind, | |
| parent, | |
| parent_item, | |
| last_field && idx == bfields.len() - 1, | |
| result, | |
| struct_layout, | |
| fields, | |
| methods, | |
| ( | |
| &unit_field_name, | |
| &unit_field_ty, | |
| &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, ¶m_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_raw_getter_name( | |
| ctx: &BindgenContext, | |
| bitfield: &Bitfield, | |
| ) -> proc_macro2::TokenStream { | |
| let name = bitfield.getter_name(); | |
| let name = ctx.rust_ident_raw(format!("{name}_raw")); | |
| 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 } | |
| } | |
| fn bitfield_raw_setter_name( | |
| ctx: &BindgenContext, | |
| bitfield: &Bitfield, | |
| ) -> proc_macro2::TokenStream { | |
| let setter = bitfield.setter_name(); | |
| let setter = ctx.rust_ident_raw(format!("{setter}_raw")); | |
| quote! { #setter } | |
| } | |
| impl<'a> FieldCodegen<'a> for Bitfield { | |
| type Extra = ( | |
| &'a str, | |
| &'a syn::Type, | |
| &'a mut bool, | |
| &'a mut FieldVisibilityKind, | |
| ); | |
| fn codegen<F, M>( | |
| &self, | |
| ctx: &BindgenContext, | |
| visibility_kind: FieldVisibilityKind, | |
| _accessor_kind: FieldAccessorKind, | |
| parent: &CompInfo, | |
| parent_item: &Item, | |
| _last_field: bool, | |
| _result: &mut CodegenResult, | |
| struct_layout: &mut StructLayoutTracker, | |
| _fields: &mut F, | |
| methods: &mut M, | |
| ( | |
| unit_field_name, | |
| unit_field_ty, | |
| bitfield_representable_as_int, | |
| bitfield_visibility, | |
| ): ( | |
| &'a str, | |
| &'a syn::Type, | |
| &mut bool, | |
| &'a mut FieldVisibilityKind, | |
| ), | |
| ) where | |
| F: Extend<proc_macro2::TokenStream>, | |
| M: Extend<proc_macro2::TokenStream>, | |
| { | |
| let prefix = ctx.trait_prefix(); | |
| let getter_name = bitfield_getter_name(ctx, self); | |
| let setter_name = bitfield_setter_name(ctx, self); | |
| let raw_getter_name = bitfield_raw_getter_name(ctx, self); | |
| let raw_setter_name = bitfield_raw_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_kind = bitfield_ty.canonical_type(ctx).kind(); | |
| let bitfield_ty_ident = bitfield_ty.name(); | |
| let bitfield_ty_layout = bitfield_ty | |
| .layout(ctx) | |
| .expect("Bitfield without layout? Gah!"); | |
| let bitfield_int_ty = | |
| if let Some(int_ty) = helpers::integer_type(bitfield_ty_layout) { | |
| *bitfield_representable_as_int = true; | |
| int_ty | |
| } else { | |
| *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, | |
| field_type_name: bitfield_ty_ident, | |
| }) | |
| }) | |
| }); | |
| *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 { | |
| self.#unit_field_ident.as_ref().get(#offset, #width) | |
| as #bitfield_int_ty | |
| as _ | |
| } | |
| #[inline] | |
| #access_spec fn #setter_name(&mut self, val: #bitfield_ty) { | |
| let val: #bitfield_int_ty = val as _; | |
| self.#unit_field_ident.as_mut().set( | |
| #offset, | |
| #width, | |
| val as u64 | |
| ) | |
| } | |
| })); | |
| methods.extend(Some(quote! { | |
| #[inline] | |
| #access_spec unsafe fn #raw_getter_name(this: *const Self) -> #bitfield_ty { | |
| unsafe { | |
| <#unit_field_ty>::raw_get( | |
| (*::#prefix::ptr::addr_of!((*this).#unit_field_ident)).as_ref() as *const _, | |
| #offset, | |
| #width, | |
| ) as #bitfield_int_ty | |
| as _ | |
| } | |
| } | |
| #[inline] | |
| #access_spec unsafe fn #raw_setter_name(this: *mut Self, val: #bitfield_ty) { | |
| unsafe { | |
| let val: #bitfield_int_ty = val as _; | |
| <#unit_field_ty>::raw_set( | |
| (*::#prefix::ptr::addr_of_mut!((*this).#unit_field_ident)).as_mut() as *mut _, | |
| #offset, | |
| #width, | |
| val as u64, | |
| ) | |
| } | |
| } | |
| })); | |
| } else { | |
| let is_rust_union = | |
| parent.is_union() && struct_layout.is_rust_union(); | |
| let get = quote! { self.#unit_field_ident.get_const::<#offset, #width>() as #bitfield_int_ty }; | |
| let raw_get = quote! { | |
| <#unit_field_ty>::raw_get_const::<#offset, #width>( | |
| ::#prefix::ptr::addr_of!((*this).#unit_field_ident), | |
| ) as #bitfield_int_ty | |
| }; | |
| let (getter_inner, raw_getter_inner) = match bitfield_ty_kind { | |
| TypeKind::Int(IntKind::Bool) => { | |
| (quote! { #get != 0 }, quote! { #raw_get != 0 }) | |
| } | |
| TypeKind::Enum(..) => ( | |
| quote! { ::#prefix::mem::transmute(#get) }, | |
| quote! { ::#prefix::mem::transmute(#raw_get) }, | |
| ), | |
| _ => (quote! { #get as _ }, quote! { #raw_get as _ }), | |
| }; | |
| let getter_body = if is_rust_union || | |
| matches!(bitfield_ty_kind, TypeKind::Enum(..)) | |
| { | |
| quote! { unsafe { #getter_inner } } | |
| } else { | |
| getter_inner | |
| }; | |
| let setter_inner = quote! { | |
| let val: #bitfield_int_ty = val as _; | |
| self.#unit_field_ident.set_const::<#offset, #width>(val as u64) | |
| }; | |
| let setter_body = if is_rust_union { | |
| quote! { unsafe { #setter_inner } } | |
| } else { | |
| setter_inner | |
| }; | |
| methods.extend(Some(quote! { | |
| #[inline] | |
| #access_spec fn #getter_name(&self) -> #bitfield_ty { | |
| #getter_body | |
| } | |
| #[inline] | |
| #access_spec fn #setter_name(&mut self, val: #bitfield_ty) { | |
| #setter_body | |
| } | |
| })); | |
| methods.extend(Some(quote! { | |
| #[inline] | |
| #access_spec unsafe fn #raw_getter_name(this: *const Self) -> #bitfield_ty { | |
| unsafe { #raw_getter_inner } | |
| } | |
| #[inline] | |
| #access_spec unsafe fn #raw_setter_name(this: *mut Self, val: #bitfield_ty) { | |
| unsafe { | |
| let val: #bitfield_int_ty = val as _; | |
| <#unit_field_ty>::raw_set_const::<#offset, #width>( | |
| ::#prefix::ptr::addr_of_mut!((*this).#unit_field_ident), | |
| val as u64, | |
| ) | |
| } | |
| } | |
| })); | |
| } | |
| } | |
| } | |
| impl CodeGenerator for CompInfo { | |
| type Extra = Item; | |
| type Return = (); | |
| fn codegen( | |
| &self, | |
| ctx: &BindgenContext, | |
| result: &mut CodegenResult<'_>, | |
| item: &Item, | |
| ) { | |
| debug!("<CompInfo as CodeGenerator>::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, | |
| ); | |
| 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> | |
| > , | |
| }); | |
| } | |
| 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); | |
| let field_decls = self.fields(); | |
| for (idx, field) in field_decls.iter().enumerate() { | |
| field.codegen( | |
| ctx, | |
| visibility, | |
| struct_accessor_kind, | |
| self, | |
| item, | |
| idx == field_decls.len() - 1, | |
| 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); | |
| struct_layout.saw_field_with_layout( | |
| "_address", | |
| layout, | |
| /* offset = */ Some(0), | |
| ); | |
| fields.push(quote! { | |
| pub _address: u8, | |
| }); | |
| } | |
| } | |
| if is_opaque { | |
| match layout { | |
| Some(l) => { | |
| explicit_align = Some(l.align); | |
| let ty = helpers::blob(ctx, l, false); | |
| fields.push(quote! { | |
| pub _bindgen_opaque_blob: #ty , | |
| }); | |
| } | |
| None => { | |
| if !forward_decl { | |
| 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); | |
| } | |
| } | |
| } | |
| } else if is_union && !forward_decl { | |
| if let Some(layout) = layout { | |
| // TODO(emilio): It'd be nice to unify this with the struct path above somehow. | |
| if struct_layout.requires_explicit_align(layout) { | |
| explicit_align = Some(layout.align); | |
| } | |
| if !struct_layout.is_rust_union() { | |
| let ty = helpers::blob(ctx, layout, false); | |
| fields.push(quote! { | |
| pub bindgen_union_field: #ty, | |
| }); | |
| } | |
| } | |
| } | |
| if forward_decl { | |
| fields.push(quote! { | |
| _unused: [u8; 0], | |
| }); | |
| } | |
| let (flex_array_generic, flex_inner_ty) = if ctx.options().flexarray_dst | |
| { | |
| match self.flex_array_member(ctx) { | |
| Some(ty) => { | |
| let inner = ty.to_rust_ty_or_opaque(ctx, &()); | |
| ( | |
| Some(quote! { FAM: ?Sized = [ #inner; 0 ] }), | |
| Some(quote! { #inner }), | |
| ) | |
| } | |
| None => (None, None), | |
| } | |
| } else { | |
| (None, None) | |
| }; | |
| // Generics, including the flexible array member. | |
| // | |
| // generics - generic parameters for the struct declaration | |
| // impl_generics_labels - generic parameters for `impl<...>` | |
| // impl_generics_params - generic parameters for `impl structname<...>` | |
| // | |
| // `impl` blocks are for non-FAM related impls like Default, etc | |
| let (generics, impl_generics_labels, impl_generics_params) = | |
| if !generic_param_names.is_empty() || flex_array_generic.is_some() { | |
| let (flex_sized, flex_fam) = match flex_inner_ty.as_ref() { | |
| None => (None, None), | |
| Some(ty) => ( | |
| Some(quote! { [ #ty; 0 ] }), | |
| Some(quote! { FAM: ?Sized = [ #ty; 0 ] }), | |
| ), | |
| }; | |
| ( | |
| quote! { | |
| < #( #generic_param_names , )* #flex_fam > | |
| }, | |
| quote! { | |
| < #( #generic_param_names , )* > | |
| }, | |
| quote! { | |
| < #( #generic_param_names , )* #flex_sized > | |
| }, | |
| ) | |
| } else { | |
| (quote! {}, quote! {}, 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; | |
| let needs_flexarray_impl = flex_array_generic.is_some(); | |
| 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); | |
| 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")); | |
| } | |
| // Ensure that the struct has the correct alignment even in presence of alignas and co. | |
| if let Some(explicit) = explicit_align { | |
| // If we need explicit alignment and can do it, we prefer to insert a dummy field at | |
| // the beginning of the struct. This avoids hitting | |
| // https://github.com/rust-lang/rust-bindgen/issues/2179 | |
| // Do it for bitfields only for now for backwards compat. | |
| // | |
| // (Note that, if the target's primitive type alignment is *not* sufficiently | |
| // aligned, as in the case of u64 on a 32-bit system, we should not insert the dummy | |
| // field, hence checking that `explicit` is less-than-or-equal-to the target primitive | |
| // type's alignemnt.) | |
| let target_primitive_align = Layout::for_size(ctx, explicit).align; | |
| if self.has_bitfields() && | |
| explicit <= 8 && | |
| target_primitive_align >= explicit | |
| { | |
| let align_ty = match explicit { | |
| 8 => quote! { u64 }, | |
| 4 => quote! { u32 }, | |
| 2 => quote! { u16 }, | |
| _ => quote! { u8 }, | |
| }; | |
| let align_field = quote! { | |
| pub _bindgen_align: [#align_ty; 0], | |
| }; | |
| fields.insert(0, align_field); | |
| } else { | |
| let explicit = helpers::ast_ty::int_expr(explicit as i64); | |
| attributes.push(quote! { | |
| #[repr(align(#explicit))] | |
| }); | |
| } | |
| } | |
| let derivable_traits = if self.is_forward_declaration() { | |
| // The only trait we can derive for forward declared types is `Debug`, | |
| // since we don't know anything about the layout or type. | |
| let mut derivable_traits = DerivableTraits::empty(); | |
| if !item.annotations().disallow_debug() { | |
| derivable_traits |= DerivableTraits::DEBUG; | |
| } | |
| derivable_traits | |
| } else { | |
| 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(); | |
| utils::call_discovered_item_callback(ctx, item, || match self.kind() { | |
| CompKind::Struct => DiscoveredItem::Struct { | |
| original_name: item | |
| .kind() | |
| .expect_type() | |
| .name() | |
| .map(String::from), | |
| final_name: canonical_ident.to_string(), | |
| }, | |
| CompKind::Union => DiscoveredItem::Union { | |
| original_name: item | |
| .kind() | |
| .expect_type() | |
| .name() | |
| .map(String::from), | |
| final_name: canonical_ident.to_string(), | |
| }, | |
| }); | |
| // 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. | |
| append_custom_derives(&mut derives, &custom_derives); | |
| if !derives.is_empty() { | |
| attributes.push(attributes::derives(&derives)); | |
| } | |
| attributes.extend( | |
| item.annotations() | |
| .attributes() | |
| .iter() | |
| .map(|s| s.parse().unwrap()), | |
| ); | |
| let custom_attributes = ctx.options().all_callbacks(|cb| { | |
| cb.add_attributes(&AttributeInfo { | |
| name: &canonical_name, | |
| kind: if is_rust_union { | |
| DeriveTypeKind::Union | |
| } else { | |
| DeriveTypeKind::Struct | |
| }, | |
| }) | |
| }); | |
| attributes.extend(custom_attributes.iter().map(|s| s.parse().unwrap())); | |
| 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 {canonical_ident} has an unknown attribute that may affect layout"); | |
| } | |
| 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 compile_time = ctx.options().rust_features().offset_of; | |
| let fn_name = if compile_time { | |
| None | |
| } else { | |
| let fn_name = | |
| format!("bindgen_test_layout_{canonical_ident}"); | |
| Some(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 size_of_err = format!("Size of {canonical_ident}"); | |
| let align_of_err = | |
| format!("Alignment of {canonical_ident}"); | |
| let check_struct_align = if compile_time { | |
| quote! { | |
| [#align_of_err][#align_of_expr - #align]; | |
| } | |
| } else { | |
| quote! { | |
| assert_eq!(#align_of_expr, #align, #align_of_err); | |
| } | |
| }; | |
| 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| { | |
| let Field::DataMember(field) = field else { return None }; | |
| let name = field.name()?; | |
| field.offset().map(|offset| { | |
| let field_offset = offset / 8; | |
| let field_name = ctx.rust_ident(name); | |
| let offset_of_err = format!("Offset of field: {canonical_ident}::{field_name}"); | |
| if compile_time { | |
| quote! { | |
| [#offset_of_err][ | |
| ::#prefix::mem::offset_of!(#canonical_ident, #field_name) - #field_offset | |
| ]; | |
| } | |
| } else { | |
| quote! { | |
| assert_eq!( | |
| unsafe { | |
| ::#prefix::ptr::addr_of!((*ptr).#field_name) as usize - ptr as usize | |
| }, | |
| #field_offset, | |
| #offset_of_err | |
| ); | |
| } | |
| } | |
| }) | |
| }) | |
| .collect() | |
| }; | |
| let uninit_decl = if check_field_offset.is_empty() || | |
| compile_time | |
| { | |
| None | |
| } else { | |
| // 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(); | |
| }) | |
| }; | |
| if compile_time { | |
| result.push(quote! { | |
| #[allow(clippy::unnecessary_operation, clippy::identity_op)] | |
| const _: () = { | |
| [#size_of_err][#size_of_expr - #size]; | |
| #check_struct_align | |
| #( #check_field_offset )* | |
| }; | |
| }); | |
| } else { | |
| result.push(quote! { | |
| #[test] | |
| fn #fn_name() { | |
| #uninit_decl | |
| assert_eq!(#size_of_expr, #size, #size_of_err); | |
| #check_struct_align | |
| #( #check_field_offset )* | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| let mut method_names = Default::default(); | |
| let discovered_id = DiscoveredItemId::new(item.id().as_usize()); | |
| if ctx.options().codegen_config.methods() { | |
| for method in self.methods() { | |
| assert_ne!(method.kind(), MethodKind::Constructor); | |
| method.codegen_method( | |
| ctx, | |
| &mut methods, | |
| &mut method_names, | |
| result, | |
| self, | |
| discovered_id, | |
| ); | |
| } | |
| } | |
| 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, | |
| discovered_id, | |
| ); | |
| } | |
| } | |
| 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, | |
| discovered_id, | |
| ); | |
| } | |
| } | |
| } | |
| // 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 #impl_generics_params | |
| }; | |
| if needs_clone_impl { | |
| result.push(quote! { | |
| impl #impl_generics_labels Clone for #ty_for_impl { | |
| fn clone(&self) -> Self { *self } | |
| } | |
| }); | |
| } | |
| if needs_flexarray_impl { | |
| result.push(self.generate_flexarray( | |
| ctx, | |
| &canonical_ident, | |
| flex_inner_ty.as_ref(), | |
| &generic_param_names, | |
| &impl_generics_labels, | |
| )); | |
| } | |
| if needs_default_impl { | |
| let prefix = ctx.trait_prefix(); | |
| let body = quote! { | |
| let mut s = ::#prefix::mem::MaybeUninit::<Self>::uninit(); | |
| unsafe { | |
| ::#prefix::ptr::write_bytes(s.as_mut_ptr(), 0, 1); | |
| s.assume_init() | |
| } | |
| }; | |
| // 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 compatibility is | |
| // involved. | |
| result.push(quote! { | |
| impl #impl_generics_labels 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 #impl_generics_labels ::#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() { | |
| quote! {} | |
| } else { | |
| let bounds = generic_param_names.iter().map(|t| { | |
| quote! { #t: PartialEq } | |
| }); | |
| quote! { where #( #bounds ),* } | |
| }; | |
| let prefix = ctx.trait_prefix(); | |
| result.push(quote! { | |
| impl #impl_generics_labels ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds { | |
| #impl_ | |
| } | |
| }); | |
| } | |
| } | |
| if !methods.is_empty() { | |
| result.push(quote! { | |
| impl #impl_generics_labels #ty_for_impl { | |
| #( #methods )* | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| impl CompInfo { | |
| fn generate_flexarray( | |
| &self, | |
| ctx: &BindgenContext, | |
| canonical_ident: &Ident, | |
| flex_inner_ty: Option<&proc_macro2::TokenStream>, | |
| generic_param_names: &[Ident], | |
| impl_generics_labels: &proc_macro2::TokenStream, | |
| ) -> proc_macro2::TokenStream { | |
| let prefix = ctx.trait_prefix(); | |
| let flex_array = flex_inner_ty.as_ref().map(|ty| quote! { [ #ty ] }); | |
| let dst_ty_for_impl = quote! { | |
| #canonical_ident < #( #generic_param_names , )* #flex_array > | |
| }; | |
| let sized_ty_for_impl = quote! { | |
| #canonical_ident < #( #generic_param_names , )* [ #flex_inner_ty; 0 ] > | |
| }; | |
| let layout = if ctx.options().rust_features().layout_for_ptr { | |
| quote! { | |
| pub fn layout(len: usize) -> ::#prefix::alloc::Layout { | |
| // SAFETY: Null pointers are OK if we don't deref them | |
| unsafe { | |
| let p: *const Self = ::#prefix::ptr::from_raw_parts(::#prefix::ptr::null::<()>(), len); | |
| ::#prefix::alloc::Layout::for_value_raw(p) | |
| } | |
| } | |
| } | |
| } else { | |
| quote!() | |
| }; | |
| let (from_ptr_dst, from_ptr_sized) = if ctx | |
| .options() | |
| .rust_features() | |
| .ptr_metadata | |
| { | |
| let flex_ref_inner = ctx.wrap_unsafe_ops(quote! { | |
| Self::flex_ptr(self, len) | |
| }); | |
| let flex_ref_mut_inner = ctx.wrap_unsafe_ops(quote! { | |
| Self::flex_ptr_mut(self, len).assume_init() | |
| }); | |
| let flex_ptr_inner = ctx.wrap_unsafe_ops(quote! { | |
| &*::#prefix::ptr::from_raw_parts(ptr as *const (), len) | |
| }); | |
| let flex_ptr_mut_inner = ctx.wrap_unsafe_ops(quote! { | |
| // Initialize reference without ever exposing it, as its possibly uninitialized | |
| let mut uninit = ::#prefix::mem::MaybeUninit::<&mut #dst_ty_for_impl>::uninit(); | |
| (uninit.as_mut_ptr() as *mut *mut #dst_ty_for_impl) | |
| .write(::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len)); | |
| uninit | |
| }); | |
| ( | |
| quote! { | |
| #[inline] | |
| pub fn fixed(&self) -> (& #sized_ty_for_impl, usize) { | |
| unsafe { | |
| let (ptr, len) = (self as *const Self).to_raw_parts(); | |
| (&*(ptr as *const #sized_ty_for_impl), len) | |
| } | |
| } | |
| #[inline] | |
| pub fn fixed_mut(&mut self) -> (&mut #sized_ty_for_impl, usize) { | |
| unsafe { | |
| let (ptr, len) = (self as *mut Self).to_raw_parts(); | |
| (&mut *(ptr as *mut #sized_ty_for_impl), len) | |
| } | |
| } | |
| }, | |
| quote! { | |
| /// Convert a sized prefix to an unsized structure with the given length. | |
| /// | |
| /// SAFETY: Underlying storage is initialized up to at least `len` elements. | |
| pub unsafe fn flex_ref(&self, len: usize) -> &#dst_ty_for_impl { | |
| // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. | |
| #flex_ref_inner | |
| } | |
| /// Convert a mutable sized prefix to an unsized structure with the given length. | |
| /// | |
| /// SAFETY: Underlying storage is initialized up to at least `len` elements. | |
| #[inline] | |
| pub unsafe fn flex_ref_mut(&mut self, len: usize) -> &mut #dst_ty_for_impl { | |
| // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. | |
| #flex_ref_mut_inner | |
| } | |
| /// Construct DST variant from a pointer and a size. | |
| /// | |
| /// NOTE: lifetime of returned reference is not tied to any underlying storage. | |
| /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. | |
| #[inline] | |
| pub unsafe fn flex_ptr<'unbounded>(ptr: *const Self, len: usize) -> &'unbounded #dst_ty_for_impl { | |
| #flex_ptr_inner | |
| } | |
| /// Construct mutable DST variant from a pointer and a | |
| /// size. The returned `&mut` reference is initialized | |
| /// pointing to memory referenced by `ptr`, but there's | |
| /// no requirement that that memory be initialized. | |
| /// | |
| /// NOTE: lifetime of returned reference is not tied to any underlying storage. | |
| /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. | |
| #[inline] | |
| pub unsafe fn flex_ptr_mut<'unbounded>( | |
| ptr: *mut Self, | |
| len: usize, | |
| ) -> ::#prefix::mem::MaybeUninit<&'unbounded mut #dst_ty_for_impl> { | |
| #flex_ptr_mut_inner | |
| } | |
| }, | |
| ) | |
| } else { | |
| (quote!(), quote!()) | |
| }; | |
| quote! { | |
| impl #impl_generics_labels #dst_ty_for_impl { | |
| #layout | |
| #from_ptr_dst | |
| } | |
| impl #impl_generics_labels #sized_ty_for_impl { | |
| #from_ptr_sized | |
| } | |
| } | |
| } | |
| } | |
| impl Method { | |
| fn codegen_method( | |
| &self, | |
| ctx: &BindgenContext, | |
| methods: &mut Vec<proc_macro2::TokenStream>, | |
| method_names: &mut HashSet<String>, | |
| result: &mut CodegenResult<'_>, | |
| _parent: &CompInfo, | |
| parent_id: DiscoveredItemId, | |
| ) { | |
| assert!({ | |
| let cc = &ctx.options().codegen_config; | |
| match self.kind() { | |
| MethodKind::Constructor => cc.constructors(), | |
| MethodKind::Destructor | | |
| 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 Some(times_seen) = times_seen else { 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 TypeKind::Function(ref signature) = | |
| *signature_item.expect_type().kind() | |
| else { | |
| 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()); | |
| utils::call_discovered_item_callback(ctx, function_item, || { | |
| DiscoveredItem::Method { | |
| parent: parent_id, | |
| final_name: 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(); | |
| exprs[0] = quote! { | |
| __bindgen_tmp.as_mut_ptr() | |
| }; | |
| let tmp_variable_decl = quote! { | |
| let mut __bindgen_tmp = ::#prefix::mem::MaybeUninit::uninit() | |
| }; | |
| 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(quote! { | |
| __bindgen_tmp.assume_init() | |
| }); | |
| } | |
| let block = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*)); | |
| let mut attrs = vec![attributes::inline()]; | |
| if signature.must_use() { | |
| 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, Default)] | |
| 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 | |
| #[default] | |
| 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 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 FromStr for EnumVariation { | |
| type Err = std::io::Error; | |
| /// Create a `EnumVariation` from a string. | |
| fn from_str(s: &str) -> Result<Self, Self::Err> { | |
| 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'." | |
| ), | |
| )), | |
| } | |
| } | |
| } | |
| struct EnumBuilder { | |
| /// Type identifier of the enum. | |
| /// | |
| /// This is the base name, i.e. for `ModuleConst` enums, this does not include the module name. | |
| enum_type: Ident, | |
| /// Attributes applying to the enum type | |
| attrs: Vec<proc_macro2::TokenStream>, | |
| /// The representation of the enum, e.g. `u32`. | |
| repr: syn::Type, | |
| /// The enum kind we are generating | |
| kind: EnumBuilderKind, | |
| /// A list of all variants this enum has. | |
| enum_variants: Vec<EnumVariantInfo>, | |
| } | |
| /// A helper type to construct different enum variations. | |
| enum EnumBuilderKind { | |
| Rust { | |
| non_exhaustive: bool, | |
| }, | |
| NewType { | |
| is_bitfield: bool, | |
| is_global: bool, | |
| /// if the enum is named or not. | |
| is_anonymous: bool, | |
| }, | |
| Consts { | |
| needs_typedef: bool, | |
| }, | |
| ModuleConsts { | |
| module_name: Ident, | |
| }, | |
| } | |
| impl EnumBuilder { | |
| /// Returns true if the builder is for a rustified enum. | |
| fn is_rust_enum(&self) -> bool { | |
| matches!(self.kind, EnumBuilderKind::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: &str, | |
| attrs: Vec<proc_macro2::TokenStream>, | |
| repr: &syn::Type, | |
| enum_variation: EnumVariation, | |
| has_typedef: bool, | |
| enum_is_anonymous: bool, | |
| ) -> Self { | |
| let ident = Ident::new(name, Span::call_site()); | |
| // For most variants this is the same | |
| let mut enum_ty = ident.clone(); | |
| let kind = match enum_variation { | |
| EnumVariation::NewType { | |
| is_bitfield, | |
| is_global, | |
| } => EnumBuilderKind::NewType { | |
| is_bitfield, | |
| is_global, | |
| is_anonymous: enum_is_anonymous, | |
| }, | |
| EnumVariation::Rust { non_exhaustive } => { | |
| EnumBuilderKind::Rust { non_exhaustive } | |
| } | |
| EnumVariation::Consts => EnumBuilderKind::Consts { | |
| needs_typedef: !has_typedef, | |
| }, | |
| EnumVariation::ModuleConsts => { | |
| enum_ty = Ident::new( | |
| CONSTIFIED_ENUM_MODULE_REPR_NAME, | |
| Span::call_site(), | |
| ); | |
| EnumBuilderKind::ModuleConsts { | |
| module_name: ident.clone(), | |
| } | |
| } | |
| }; | |
| EnumBuilder { | |
| enum_type: enum_ty, | |
| attrs, | |
| repr: repr.clone(), | |
| kind, | |
| enum_variants: vec![], | |
| } | |
| } | |
| /// Add a variant to this enum. | |
| fn with_variant( | |
| mut self, | |
| ctx: &BindgenContext, | |
| variant: &EnumVariant, | |
| variant_doc: proc_macro2::TokenStream, | |
| mangling_prefix: Option<&str>, | |
| rust_ty: &syn::Type, | |
| 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(u64::from(v)) | |
| } | |
| EnumVariantValue::Boolean(v) => quote!(#v), | |
| EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), | |
| EnumVariantValue::Unsigned(v) => helpers::ast_ty::uint_expr(v), | |
| }; | |
| match self.kind { | |
| EnumBuilderKind::Rust { .. } => { | |
| let name = ctx.rust_ident(variant_name); | |
| self.enum_variants.push(EnumVariantInfo { | |
| variant_name: name, | |
| variant_doc, | |
| value: expr, | |
| }); | |
| self | |
| } | |
| EnumBuilderKind::NewType { is_global, .. } => { | |
| let variant_ident = if is_ty_named && !is_global { | |
| ctx.rust_ident(variant_name) | |
| } else { | |
| ctx.rust_ident(match mangling_prefix { | |
| Some(prefix) => { | |
| Cow::Owned(format!("{prefix}_{variant_name}")) | |
| } | |
| None => variant_name, | |
| }) | |
| }; | |
| self.enum_variants.push(EnumVariantInfo { | |
| variant_name: variant_ident, | |
| variant_doc, | |
| value: quote! { #rust_ty ( #expr )}, | |
| }); | |
| self | |
| } | |
| EnumBuilderKind::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); | |
| self.enum_variants.push(EnumVariantInfo { | |
| variant_name: ident, | |
| variant_doc, | |
| value: quote! { #expr }, | |
| }); | |
| self | |
| } | |
| EnumBuilderKind::ModuleConsts { .. } => { | |
| let name = ctx.rust_ident(variant_name); | |
| self.enum_variants.push(EnumVariantInfo { | |
| variant_name: name, | |
| variant_doc, | |
| value: quote! { #expr }, | |
| }); | |
| self | |
| } | |
| } | |
| } | |
| fn newtype_bitfield_impl( | |
| prefix: &Ident, | |
| rust_ty: &syn::Type, | |
| ) -> proc_macro2::TokenStream { | |
| let rust_ty_name = &rust_ty; | |
| 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) | |
| } | |
| } | |
| impl ::#prefix::ops::BitOrAssign for #rust_ty { | |
| #[inline] | |
| fn bitor_assign(&mut self, rhs: #rust_ty) { | |
| self.0 |= rhs.0; | |
| } | |
| } | |
| 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) | |
| } | |
| } | |
| impl ::#prefix::ops::BitAndAssign for #rust_ty { | |
| #[inline] | |
| fn bitand_assign(&mut self, rhs: #rust_ty) { | |
| self.0 &= rhs.0; | |
| } | |
| } | |
| } | |
| } | |
| fn build( | |
| self, | |
| ctx: &BindgenContext, | |
| rust_ty: &syn::Type, | |
| ) -> proc_macro2::TokenStream { | |
| let enum_ident = self.enum_type; | |
| // 1. Construct a list of the enum variants | |
| let variants = match self.kind { | |
| EnumBuilderKind::Rust { .. } => { | |
| let mut variants = vec![]; | |
| for v in self.enum_variants { | |
| let variant_doc = &v.variant_doc; | |
| let variant_ident = &v.variant_name; | |
| let variant_value = &v.value; | |
| variants.push(quote! { | |
| #variant_doc | |
| #variant_ident = #variant_value, | |
| }); | |
| } | |
| if variants.is_empty() { | |
| variants.push( | |
| quote! {__bindgen_cannot_repr_c_on_empty_enum = 0,}, | |
| ); | |
| } | |
| variants | |
| } | |
| EnumBuilderKind::NewType { .. } => { | |
| let mut variants = vec![]; | |
| for v in self.enum_variants { | |
| let variant_doc = &v.variant_doc; | |
| let variant_ident = &v.variant_name; | |
| let variant_value = &v.value; | |
| variants.push(quote! { | |
| #variant_doc | |
| pub const #variant_ident: #enum_ident = #variant_value; | |
| }); | |
| } | |
| variants | |
| } | |
| EnumBuilderKind::Consts { .. } | | |
| EnumBuilderKind::ModuleConsts { .. } => { | |
| let mut variants = vec![]; | |
| for v in self.enum_variants { | |
| let variant_doc = &v.variant_doc; | |
| let variant_ident = &v.variant_name; | |
| let variant_value = &v.value; | |
| variants.push(quote! { | |
| #variant_doc | |
| pub const #variant_ident: #enum_ident = #variant_value; | |
| }); | |
| } | |
| variants | |
| } | |
| }; | |
| let attrs = self.attrs; | |
| let enum_repr = &self.repr; | |
| // 2. Generate the enum representation | |
| match self.kind { | |
| EnumBuilderKind::Rust { non_exhaustive } => { | |
| let non_exhaustive_opt = | |
| non_exhaustive.then(attributes::non_exhaustive); | |
| quote! { | |
| // Note: repr is on top of attrs to keep the test expectations diff small. | |
| // a future commit could move it further down. | |
| #[repr(#enum_repr)] | |
| #non_exhaustive_opt | |
| #( #attrs )* | |
| pub enum #enum_ident { | |
| #( #variants )* | |
| } | |
| } | |
| } | |
| EnumBuilderKind::NewType { | |
| is_bitfield, | |
| is_global, | |
| is_anonymous, | |
| } => { | |
| // There doesn't seem to be a technical reason why we generate | |
| // anon enum variants as global constants. | |
| // We keep this behavior to avoid breaking changes in the bindings. | |
| let impl_variants = if is_anonymous || is_global { | |
| quote! { | |
| #( #variants )* | |
| } | |
| } else { | |
| quote! { | |
| impl #enum_ident { | |
| #( #variants )* | |
| } | |
| } | |
| }; | |
| let prefix = ctx.trait_prefix(); | |
| let bitfield_impl_opt = is_bitfield | |
| .then(|| Self::newtype_bitfield_impl(&prefix, rust_ty)); | |
| quote! { | |
| // Previously variant impls where before the enum definition. | |
| // lets keep this as is for now, to reduce the diff in generated bindings. | |
| #impl_variants | |
| #bitfield_impl_opt | |
| #[repr(transparent)] | |
| #( #attrs )* | |
| pub struct #enum_ident (pub #enum_repr); | |
| } | |
| } | |
| EnumBuilderKind::Consts { needs_typedef } => { | |
| let typedef_opt = needs_typedef.then(|| { | |
| quote! { | |
| #( #attrs )* | |
| pub type #enum_ident = #enum_repr; | |
| } | |
| }); | |
| quote! { | |
| #( #variants )* | |
| #typedef_opt | |
| } | |
| } | |
| EnumBuilderKind::ModuleConsts { module_name, .. } => { | |
| quote! { | |
| // todo: Probably some attributes, e.g. `cfg` should apply to the `mod`. | |
| pub mod #module_name { | |
| #[allow(unused_imports)] | |
| use super::*; | |
| #( #attrs )* | |
| pub type #enum_ident = #enum_repr; | |
| #( #variants )* | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| impl CodeGenerator for Enum { | |
| type Extra = Item; | |
| type Return = (); | |
| fn codegen( | |
| &self, | |
| ctx: &BindgenContext, | |
| result: &mut CodegenResult<'_>, | |
| item: &Item, | |
| ) { | |
| debug!("<Enum as CodeGenerator>::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 = if let Some(repr) = repr { | |
| match *repr.canonical_type(ctx).kind() { | |
| TypeKind::Int(int_kind) => int_kind, | |
| _ => panic!("Unexpected type as enum repr"), | |
| } | |
| } else { | |
| 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: {signed}, size: {size}" | |
| ); | |
| IntKind::I32 | |
| } | |
| }; | |
| repr_translated = | |
| Type::new(None, None, TypeKind::Int(translated), false); | |
| &repr_translated | |
| } | |
| }; | |
| let mut attrs = vec![]; | |
| 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() { | |
| 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. | |
| append_custom_derives(&mut derives, &custom_derives); | |
| attrs.extend( | |
| item.annotations() | |
| .attributes() | |
| .iter() | |
| .map(|s| s.parse().unwrap()), | |
| ); | |
| // The custom attribute callback may return a list of attributes; | |
| // add them to the end of the list. | |
| let custom_attributes = ctx.options().all_callbacks(|cb| { | |
| cb.add_attributes(&AttributeInfo { | |
| name: &name, | |
| kind: DeriveTypeKind::Enum, | |
| }) | |
| }); | |
| attrs.extend(custom_attributes.iter().map(|s| s.parse().unwrap())); | |
| 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()); | |
| utils::call_discovered_item_callback(ctx, item, || { | |
| DiscoveredItem::Enum { | |
| final_name: name.clone(), | |
| } | |
| }); | |
| let mut builder = EnumBuilder::new( | |
| &name, | |
| attrs, | |
| &repr, | |
| variation, | |
| has_typedef, | |
| enum_ty.name().is_none(), | |
| ); | |
| // 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; | |
| } | |
| let variant_doc = if let Some(comment) = variant.doc_comment(ctx) { | |
| attributes::doc(&comment) | |
| } else { | |
| quote! {} | |
| }; | |
| 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() { | |
| 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, | |
| result, | |
| ); | |
| } | |
| } else { | |
| builder = builder.with_variant( | |
| ctx, | |
| variant, | |
| variant_doc, | |
| constant_mangling_prefix, | |
| &enum_rust_ty, | |
| enum_ty.name().is_some(), | |
| ); | |
| } | |
| } | |
| Entry::Vacant(entry) => { | |
| builder = builder.with_variant( | |
| ctx, | |
| variant, | |
| variant_doc, | |
| constant_mangling_prefix, | |
| &enum_rust_ty, | |
| 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, | |
| result, | |
| ); | |
| } | |
| entry.insert(variant_name); | |
| } | |
| } | |
| } | |
| let item = builder.build(ctx, &enum_rust_ty); | |
| result.push(item); | |
| } | |
| } | |
| struct EnumVariantInfo { | |
| variant_name: Ident, | |
| variant_doc: proc_macro2::TokenStream, | |
| value: proc_macro2::TokenStream, | |
| } | |
| /// Enum for the default type of macro constants. | |
| #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] | |
| pub enum MacroTypeVariation { | |
| /// Use i32 or i64 | |
| Signed, | |
| /// Use u32 or u64 | |
| #[default] | |
| 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 FromStr for MacroTypeVariation { | |
| type Err = std::io::Error; | |
| /// Create a `MacroTypeVariation` from a string. | |
| fn from_str(s: &str) -> Result<Self, Self::Err> { | |
| 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, Default)] | |
| pub enum AliasVariation { | |
| /// Convert to regular Rust alias | |
| #[default] | |
| TypeAlias, | |
| /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)] | |
| NewType, | |
| /// Same as `NewType` 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 FromStr for AliasVariation { | |
| type Err = std::io::Error; | |
| /// Create an `AliasVariation` from a string. | |
| fn from_str(s: &str) -> Result<Self, Self::Err> { | |
| 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, Default)] | |
| pub enum NonCopyUnionStyle { | |
| /// Wrap members in a type generated by `bindgen`. | |
| #[default] | |
| 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 FromStr for NonCopyUnionStyle { | |
| type Err = std::io::Error; | |
| fn from_str(s: &str) -> Result<Self, Self::Err> { | |
| 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<Layout>; | |
| /// Do not override this provided trait method. | |
| fn try_to_opaque( | |
| &self, | |
| ctx: &BindgenContext, | |
| extra: &Self::Extra, | |
| ) -> error::Result<syn::Type> { | |
| self.try_get_layout(ctx, extra) | |
| .map(|layout| helpers::blob(ctx, layout, true)) | |
| } | |
| } | |
| /// 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, true) | |
| } | |
| } | |
| impl<T> 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<syn::Type>; | |
| } | |
| /// 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: &<Self as TryToRustTyOrOpaque>::Extra, | |
| ) -> error::Result<syn::Type>; | |
| } | |
| impl<E, T> TryToRustTyOrOpaque for T | |
| where | |
| T: TryToRustTy<Extra = E> + TryToOpaque<Extra = E>, | |
| { | |
| type Extra = E; | |
| fn try_to_rust_ty_or_opaque( | |
| &self, | |
| ctx: &BindgenContext, | |
| extra: &E, | |
| ) -> error::Result<syn::Type> { | |
| self.try_to_rust_ty(ctx, extra).or_else(|_| { | |
| if let Ok(layout) = self.try_get_layout(ctx, extra) { | |
| Ok(helpers::blob(ctx, layout, true)) | |
| } else { | |
| Err(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}` traits? 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: &<Self as ToRustTyOrOpaque>::Extra, | |
| ) -> syn::Type; | |
| } | |
| impl<E, T> ToRustTyOrOpaque for T | |
| where | |
| T: TryToRustTy<Extra = E> + ToOpaque<Extra = E>, | |
| { | |
| 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<T> TryToOpaque for T | |
| where | |
| T: Copy + Into<ItemId>, | |
| { | |
| type Extra = (); | |
| fn try_get_layout( | |
| &self, | |
| ctx: &BindgenContext, | |
| _: &(), | |
| ) -> error::Result<Layout> { | |
| ctx.resolve_item((*self).into()).try_get_layout(ctx, &()) | |
| } | |
| } | |
| impl<T> TryToRustTy for T | |
| where | |
| T: Copy + Into<ItemId>, | |
| { | |
| type Extra = (); | |
| fn try_to_rust_ty( | |
| &self, | |
| ctx: &BindgenContext, | |
| _: &(), | |
| ) -> error::Result<syn::Type> { | |
| 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<Layout> { | |
| 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<syn::Type> { | |
| 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<Layout> { | |
| self.layout(ctx).ok_or(Error::NoLayoutForOpaqueBlob) | |
| } | |
| } | |
| impl TryToRustTy for Type { | |
| type Extra = Item; | |
| fn try_to_rust_ty( | |
| &self, | |
| ctx: &BindgenContext, | |
| item: &Item, | |
| ) -> error::Result<syn::Type> { | |
| 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<NonZero<_>>) == | |
| // 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 if ctx.options().generate_cxx_nonnull_references && | |
| matches!(self.kind(), TypeKind::Reference(_)) | |
| { | |
| // It's UB to pass null values in place of C++ references | |
| let prefix = ctx.trait_prefix(); | |
| Ok(syn::parse_quote! { ::#prefix::ptr::NonNull<#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<Layout> { | |
| item.expect_type() | |
| .layout(ctx) | |
| .ok_or(Error::NoLayoutForOpaqueBlob) | |
| } | |
| } | |
| impl TryToRustTy for TemplateInstantiation { | |
| type Extra = Item; | |
| fn try_to_rust_ty( | |
| &self, | |
| ctx: &BindgenContext, | |
| item: &Item, | |
| ) -> error::Result<syn::Type> { | |
| if self.is_opaque(ctx, item) { | |
| return Err(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::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::<error::Result<Vec<_>>>()?; | |
| 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<syn::Type> { | |
| // 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::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<u32>; | |
| fn codegen( | |
| &self, | |
| ctx: &BindgenContext, | |
| result: &mut CodegenResult<'_>, | |
| item: &Item, | |
| ) -> Self::Return { | |
| debug!("<Function as CodeGenerator>::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 TypeKind::Function(ref signature) = *signature.kind() else { | |
| 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; | |
| } | |
| } | |
| let is_pure_virtual = match self.kind() { | |
| FunctionKind::Method(ref method_kind) => { | |
| method_kind.is_pure_virtual() | |
| } | |
| FunctionKind::Function => false, | |
| }; | |
| if is_pure_virtual && !ctx.options().generate_pure_virtual_functions { | |
| // Pure virtual methods have no actual symbol, so we can't generate | |
| // something meaningful for them. Downstream code postprocessors | |
| // might want to find out about them. | |
| return None; | |
| } | |
| let is_dynamic_function = match self.kind() { | |
| FunctionKind::Function => { | |
| ctx.options().dynamic_library_name.is_some() | |
| } | |
| FunctionKind::Method(_) => 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 true { | |
| 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::UnsupportedAbi(_)) { | |
| unsupported_abi_diagnostic( | |
| name, | |
| signature.is_variadic(), | |
| item.location(), | |
| ctx, | |
| &err, | |
| ); | |
| } | |
| return None; | |
| } | |
| Ok(ClangAbi::Unknown(unknown_abi)) => { | |
| panic!( | |
| "Invalid or unknown abi {unknown_abi:?} for function {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(); | |
| } | |
| utils::call_discovered_item_callback(ctx, item, || { | |
| DiscoveredItem::Function { | |
| final_name: canonical_name.clone(), | |
| } | |
| }); | |
| let link_name_attr = self.link_name().or_else(|| { | |
| let mangled_name = mangled_name.unwrap_or(name); | |
| (!utils::names_will_be_identical_after_mangling( | |
| &canonical_name, | |
| mangled_name, | |
| Some(abi), | |
| )) | |
| .then_some(mangled_name) | |
| }); | |
| if let Some(link_name) = link_name_attr { | |
| if !is_dynamic_function { | |
| attributes.push(attributes::link_name::<false>(link_name)); | |
| } | |
| } | |
| let mut block_attributes = quote! {}; | |
| for attr in &ctx.options().extern_block_attrs { | |
| let parsed_attr = proc_macro2::TokenStream::from_str(attr).unwrap_or_else( | |
| |err| { | |
| panic!( | |
| "Error parsing extern fn block attribute `{attr}`: {err}" | |
| ) | |
| }, | |
| ); | |
| block_attributes.extend(quote! { | |
| #parsed_attr | |
| }); | |
| } | |
| let should_wrap = is_internal && | |
| ctx.options().wrap_static_fns && | |
| link_name_attr.is_none(); | |
| if should_wrap { | |
| let name = canonical_name.clone() + ctx.wrap_static_fns_suffix(); | |
| attributes.push(attributes::link_name::<true>(&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 safety = ctx | |
| .options() | |
| .rust_features | |
| .unsafe_extern_blocks | |
| .then(|| quote!(unsafe)); | |
| let tokens = quote! { | |
| #block_attributes | |
| #safety 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 ident_str = ident.to_string(); | |
| let symbol = link_name_attr.unwrap_or(&ident_str); | |
| let args_identifiers = | |
| utils::fnsig_argument_identifiers(ctx, signature); | |
| let ret_ty = utils::fnsig_return_ty(ctx, signature); | |
| result.dynamic_items().push_func( | |
| &ident, | |
| symbol, | |
| 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, | |
| ) { | |
| warn!( | |
| "Skipping {}function `{fn_name}` because the {error}", | |
| if variadic { "variadic " } else { "" }, | |
| ); | |
| #[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 `{fn_name}` because the {error}", | |
| if variadic { "variadic " } else { "" }, | |
| ), | |
| Level::Warning, | |
| ) | |
| .add_annotation( | |
| "No code will be generated for this function.", | |
| Level::Warning, | |
| ) | |
| .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::Warning) | |
| .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<proc_macro2::TokenStream>, | |
| 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 <Self as std::ops::Deref>::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<Ident> = 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<ItemId> = Default::default(); | |
| for protocol_id in &self.conforms_to { | |
| 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 TypeKind::ObjCInterface(parent) = parent else { | |
| 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<Ident> = 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 { | |
| 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 {parent_struct_name} cannot be downcasted to {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<Ident> = 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::helpers::BITFIELD_UNIT; | |
| use super::serialize::CSerialize; | |
| use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque}; | |
| use crate::callbacks::DiscoveredItemId; | |
| 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_or_else( | |
| || std::env::temp_dir().join("bindgen").join("extern"), | |
| PathBuf::from, | |
| ); | |
| 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, "// {name}\n{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<super::WrapAsVariadic> { | |
| // 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<proc_macro2::TokenStream>, | |
| ) { | |
| if ctx.options().blocklisted_items.matches(BITFIELD_UNIT) || | |
| ctx.options().blocklisted_types.matches(BITFIELD_UNIT) | |
| { | |
| return; | |
| } | |
| let bitfield_unit_src = include_str!("./bitfield_unit.rs"); | |
| let bitfield_unit_src = if true { | |
| 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<proc_macro2::TokenStream>, | |
| ) { | |
| 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<proc_macro2::TokenStream>, | |
| ) { | |
| 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<proc_macro2::TokenStream>, | |
| ) { | |
| let prefix = ctx.trait_prefix(); | |
| // TODO(emilio): The fmt::Debug impl could be way nicer with | |
| // std::intrinsics::type_name, but... | |
| let union_field_decl = quote! { | |
| #[repr(C)] | |
| pub struct __BindgenUnionField<T>(::#prefix::marker::PhantomData<T>); | |
| }; | |
| let transmute = quote!(unsafe { ::#prefix::mem::transmute(self) }); | |
| let union_field_impl = quote! { | |
| impl<T> __BindgenUnionField<T> { | |
| #[inline] | |
| pub const fn new() -> Self { | |
| __BindgenUnionField(::#prefix::marker::PhantomData) | |
| } | |
| #[inline] | |
| pub const unsafe fn as_ref(&self) -> &T { | |
| #transmute | |
| } | |
| #[inline] | |
| pub const unsafe fn as_mut(&mut self) -> &mut T { | |
| #transmute | |
| } | |
| } | |
| }; | |
| let union_field_default_impl = quote! { | |
| impl<T> ::#prefix::default::Default for __BindgenUnionField<T> { | |
| #[inline] | |
| fn default() -> Self { | |
| Self::new() | |
| } | |
| } | |
| }; | |
| let union_field_clone_impl = quote! { | |
| impl<T> ::#prefix::clone::Clone for __BindgenUnionField<T> { | |
| #[inline] | |
| fn clone(&self) -> Self { | |
| *self | |
| } | |
| } | |
| }; | |
| let union_field_copy_impl = quote! { | |
| impl<T> ::#prefix::marker::Copy for __BindgenUnionField<T> {} | |
| }; | |
| let union_field_debug_impl = quote! { | |
| impl<T> ::#prefix::fmt::Debug for __BindgenUnionField<T> { | |
| 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<T> ::#prefix::hash::Hash for __BindgenUnionField<T> { | |
| fn hash<H: ::#prefix::hash::Hasher>(&self, _state: &mut H) { | |
| } | |
| } | |
| }; | |
| let union_field_partialeq_impl = quote! { | |
| impl<T> ::#prefix::cmp::PartialEq for __BindgenUnionField<T> { | |
| fn eq(&self, _other: &__BindgenUnionField<T>) -> bool { | |
| true | |
| } | |
| } | |
| }; | |
| let union_field_eq_impl = quote! { | |
| impl<T> ::#prefix::cmp::Eq for __BindgenUnionField<T> { | |
| } | |
| }; | |
| 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<proc_macro2::TokenStream>, | |
| ) { | |
| let prefix = ctx.trait_prefix(); | |
| // If the target supports `const fn`, declare eligible functions | |
| // as `const fn` else just `fn`. | |
| let const_fn = if true { | |
| quote! { const fn } | |
| } else { | |
| quote! { fn } | |
| }; | |
| let incomplete_array_decl = quote! { | |
| #[repr(C)] | |
| #[derive(Default)] | |
| pub struct __IncompleteArrayField<T>( | |
| ::#prefix::marker::PhantomData<T>, [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<T> __IncompleteArrayField<T> { | |
| #[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<T> ::#prefix::fmt::Debug for __IncompleteArrayField<T> { | |
| 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<proc_macro2::TokenStream>, | |
| ) { | |
| 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<proc_macro2::TokenStream>, | |
| ) { | |
| let complex_type = quote! { | |
| #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] | |
| #[repr(C)] | |
| pub struct __BindgenComplex<T> { | |
| 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 prepend_opaque_array_types( | |
| ctx: &BindgenContext, | |
| result: &mut Vec<proc_macro2::TokenStream>, | |
| ) { | |
| let mut tys = vec![]; | |
| // If Bindgen could only determine the size and alignment of a type, it is represented like | |
| // this. | |
| for align in ctx.opaque_array_types_needed() { | |
| let ident = if align == 1 { | |
| format_ident!("__BindgenOpaqueArray") | |
| } else { | |
| format_ident!("__BindgenOpaqueArray{align}") | |
| }; | |
| let repr = if align <= 1 { | |
| quote! { #[repr(C)] } | |
| } else { | |
| let explicit = super::helpers::ast_ty::int_expr(align as i64); | |
| quote! { #[repr(C, align(#explicit))] } | |
| }; | |
| tys.push(quote! { | |
| #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] | |
| #repr | |
| pub struct #ident<T>(pub T); | |
| impl<T: Copy + Default, const N: usize> Default for #ident<[T; N]> { | |
| fn default() -> Self { | |
| Self([<T as Default>::default(); N]) | |
| } | |
| } | |
| }); | |
| } | |
| result.splice(0..0, tys); | |
| } | |
| pub(crate) fn build_path( | |
| item: &Item, | |
| ctx: &BindgenContext, | |
| ) -> error::Result<syn::Type> { | |
| 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<syn::Type> { | |
| // 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() || arg_ty.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<Item = &'a (Option<String>, TypeId)>, | |
| >( | |
| ctx: &BindgenContext, | |
| args_iter: I, | |
| is_variadic: bool, | |
| ) -> Vec<proc_macro2::TokenStream> { | |
| let mut unnamed_arguments = 0; | |
| let mut args = args_iter | |
| .map(|(name, ty)| { | |
| let arg_ty = fnsig_argument_type(ctx, *ty); | |
| let arg_name = if let Some(ref name) = *name { | |
| ctx.rust_mangle(name).into_owned() | |
| } else { | |
| 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::<Vec<_>>(); | |
| if is_variadic { | |
| args.push(quote! { ... }); | |
| } | |
| args | |
| } | |
| pub(crate) fn fnsig_arguments( | |
| ctx: &BindgenContext, | |
| sig: &FunctionSig, | |
| ) -> Vec<proc_macro2::TokenStream> { | |
| fnsig_arguments_iter( | |
| ctx, | |
| sig.argument_types().iter(), | |
| sig.is_variadic(), | |
| ) | |
| } | |
| pub(crate) fn fnsig_argument_identifiers( | |
| ctx: &BindgenContext, | |
| sig: &FunctionSig, | |
| ) -> Vec<proc_macro2::TokenStream> { | |
| let mut unnamed_arguments = 0; | |
| let args = sig | |
| .argument_types() | |
| .iter() | |
| .map(|&(ref name, _ty)| { | |
| let arg_name = if let Some(ref name) = *name { | |
| ctx.rust_mangle(name).into_owned() | |
| } else { | |
| unnamed_arguments += 1; | |
| format!("arg{unnamed_arguments}") | |
| }; | |
| assert!(!arg_name.is_empty()); | |
| let arg_name = ctx.rust_ident(arg_name); | |
| quote! { | |
| #arg_name | |
| } | |
| }) | |
| .collect::<Vec<_>>(); | |
| 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<ClangAbi>, | |
| ) -> 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 | Abi::CUnwind)) | | |
| // 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()] != 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 | |
| } | |
| pub(super) fn call_discovered_item_callback( | |
| ctx: &BindgenContext, | |
| item: &Item, | |
| discovered_item_creator: impl Fn() -> crate::callbacks::DiscoveredItem, | |
| ) { | |
| let source_location = item.location().map(|clang_location| { | |
| let (file, line, col, byte_offset) = clang_location.location(); | |
| let file_name = file.name(); | |
| crate::callbacks::SourceLocation { | |
| line, | |
| col, | |
| byte_offset, | |
| file_name, | |
| } | |
| }); | |
| ctx.options().for_each_callback(|cb| { | |
| cb.new_item_found( | |
| DiscoveredItemId::new(item.id().as_usize()), | |
| discovered_item_creator(), | |
| source_location.as_ref(), | |
| ); | |
| }); | |
| } | |
| } |