use proc_macro2::{self, Ident, Span}; use quote::TokenStreamExt;
usecrate::{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};
let all_template_params = item.all_template_params(ctx);
if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
derivable_traits |= DerivableTraits::COPY;
if ctx.options().rust_features().builtin_clone_impls ||
!all_template_params.is_empty()
{ // FIXME: This requires extra logic if you have a big array in a // templated struct. The reason for this is that the magic: // fn clone(&self) -> Self { *self } // doesn't work for templates. // // It's not hard to fix though.
derivable_traits |= DerivableTraits::CLONE;
}
} elseif 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;
}
/// 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>)>,
}
/// 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(&mutself, name: &str) -> u32 { let counter = self.overload_counters.entry(name.into()).or_insert(0); let number = *counter;
*counter += 1;
number
}
/// 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;
}
/// 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",
)
}))
}
}
};
ifself.is_blocklisted(ctx) || result.seen(self.id()) {
debug!( "<Item as CodeGenerator>::process_before_codegen: Ignoring hidden or seen: \ self = {:?}", self
); returnfalse;
}
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 = (); typeReturn = ();
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 var_ty = self.ty(); let ty = var_ty.to_rust_ty_or_opaque(ctx, &());
iflet Some(val) = self.val() { match *val {
VarType::Bool(val) => {
result.push(quote! { #(#attrs)* pubconst#canonical_ident : #ty = #val ;
});
}
VarType::Int(val) => { let int_kind = var_ty
.into_resolver()
.through_type_aliases()
.through_type_refs()
.resolve(ctx)
.expect_type()
.as_integer()
.unwrap(); let val = if int_kind.is_signed() {
helpers::ast_ty::int_expr(val)
} else {
helpers::ast_ty::uint_expr(val as _)
};
result.push(quote! { #(#attrs)* pubconst#canonical_ident : #ty = #val ;
});
}
VarType::String(ref bytes) => { let prefix = ctx.trait_prefix();
let options = ctx.options(); let rust_features = options.rust_features;
letmut cstr_bytes = bytes.clone();
cstr_bytes.push(0); let len = proc_macro2::Literal::usize_unsuffixed(
cstr_bytes.len(),
);
// TODO: Here we ignore the type we just made up, probably // we should refactor how the variable type and ty ID work. let array_ty = quote! { [u8; #len] }; let cstr_ty = quote! { ::#prefix::ffi::CStr };
let bytes = proc_macro2::Literal::byte_string(&cstr_bytes);
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);
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() { iflet"size_t" | "ssize_t" = spelling { let layout = inner_item
.kind()
.expect_type()
.layout(ctx)
.expect("No layout?");
assert_eq!(
layout.size,
ctx.target_pointer_size(), "Target platform requires `--no-size_t-is-usize`. The size of `{}` ({}) does not match the target pointer size ({})",
spelling,
layout.size,
ctx.target_pointer_size(),
);
assert_eq!(
layout.align,
ctx.target_pointer_size(), "Target platform requires `--no-size_t-is-usize`. The alignment of `{}` ({}) does not match the target pointer size ({})",
spelling,
layout.align,
ctx.target_pointer_size(),
);
} return;
}
let 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;
}
}
impl<'a> CodeGenerator for Vtable<'a> { type Extra = Item; typeReturn = ();
fn codegen(
&self,
ctx: &BindgenContext,
result: &mut CodegenResult<'_>,
item: &Item,
) {
assert_eq!(item.id(), self.item_id);
debug_assert!(item.is_enabled_for_codegen(ctx)); let name = ctx.rust_ident(self.canonical_name(ctx));
// For now, we will only generate vtables for classes that: // - do not inherit from others (compilers merge VTable from primary parent class). // - do not contain a virtual destructor (requires ordering; platforms generate different vtables). if ctx.options().vtable_generation && self.comp_info.base_members().is_empty() && self.comp_info.destructor().is_none()
{ let class_ident = ctx.rust_ident(self.item_id.canonical_name(ctx));
let methods = self
.comp_info
.methods()
.iter()
.filter_map(|m| { if !m.is_virtual() { return None;
}
let function_item = ctx.resolve_item(m.signature()); let function = function_item.expect_function(); let signature_item = ctx.resolve_item(function.signature()); let signature = match signature_item.expect_type().kind() {
TypeKind::Function(ref sig) => sig,
_ => panic!("Function signature type mismatch"),
};
// FIXME: Is there a canonical name without the class prepended? let function_name = function_item.canonical_name(ctx);
// FIXME: Need to account for overloading with times_seen (separately from regular function path). let function_name = ctx.rust_ident(function_name); letmut args = utils::fnsig_arguments(ctx, signature); let ret = utils::fnsig_return_ty(ctx, signature);
// Although uses of instantiations don't need code generation, and are // just converted to rust types in fields, vars, etc, we take this // opportunity to generate tests for their layout here. If the // instantiation is opaque, then its presumably because we don't // properly understand it (maybe because of specializations), and so we // shouldn't emit layout tests either. if !ctx.options().layout_tests || self.is_opaque(ctx, item) { return;
}
// If there are any unbound type parameters, then we can't generate a // layout test because we aren't dealing with a concrete type with a // concrete size and alignment. if ctx.uses_any_template_parameters(item.id()) { return;
}
let layout = item.kind().expect_type().layout(ctx);
iflet Some(layout) = layout { let size = layout.size; let align = layout.align;
let name = item.full_disambiguated_name(ctx); letmut fn_name =
format!("__bindgen_test_layout_{}_instantiation", name); let times_seen = result.overload_number(&fn_name); if times_seen > 0 {
write!(&mut fn_name, "_{}", times_seen).unwrap();
}
let fn_name = ctx.rust_ident_raw(fn_name);
let prefix = ctx.trait_prefix(); let ident = item.to_rust_ty_or_opaque(ctx, &()); let size_of_expr = quote! {
::#prefix::mem::size_of::<#ident>()
}; let align_of_expr = quote! {
::#prefix::mem::align_of::<#ident>()
};
let item = quote! { #[test] fn#fn_name() {
assert_eq!(#size_of_expr, #size,
concat!("Size of template specialization: ",
stringify!(#ident)));
assert_eq!(#align_of_expr, #align,
concat!("Alignment of template specialization: ",
stringify!(#ident)));
}
};
result.push(item);
}
}
}
/// Trait for implementing the code generation of a struct or union field. trait FieldCodegen<'a> { type Extra;
impl<'a> FieldCodegen<'a> for FieldData { type Extra = ();
fn codegen<F, M>(
&self,
ctx: &BindgenContext,
parent_visibility_kind: FieldVisibilityKind,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
parent_item: &Item,
result: &mut CodegenResult,
struct_layout: &mut StructLayoutTracker,
fields: &mut F,
methods: &mut M,
_: (),
) where
F: Extend<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)
} elseiflet Some(item) = field_ty.is_incomplete_array(ctx) {
result.saw_incomplete_array();
let inner = item.to_rust_ty_or_opaque(ctx, &());
if ctx.options().enable_cxx_namespaces {
syn::parse_quote! { root::__IncompleteArrayField<#inner> }
} else {
syn::parse_quote! { __IncompleteArrayField<#inner> }
}
} else {
ty
};
letmut field = quote! {}; if ctx.options().generate_comments { iflet Some(raw_comment) = self.comment() { let comment = ctx.options().process_comment(raw_comment);
field = attributes::doc(comment);
}
}
let field_name = self
.name()
.map(|name| ctx.rust_mangle(name).into_owned())
.expect("Each field should have a name in codegen!"); let field_name = field_name.as_str(); let field_ident = ctx.rust_ident_raw(field_name);
impl BitfieldUnit { /// Get the constructor name for this bitfield unit. fn ctor_name(&self) -> proc_macro2::TokenStream { let ctor_name = Ident::new(
&format!("new_bitfield_{}", self.nth()),
Span::call_site(),
);
quote! { #ctor_name
}
}
}
impl Bitfield { /// Extend an under construction bitfield unit constructor with this /// bitfield. This sets the relevant bits on the `__bindgen_bitfield_unit` /// variable that's being constructed. fn extend_ctor_impl(
&self,
ctx: &BindgenContext,
param_name: proc_macro2::TokenStream, mut ctor_impl: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream { let bitfield_ty = ctx.resolve_type(self.ty()); let bitfield_ty_layout = bitfield_ty
.layout(ctx)
.expect("Bitfield without layout? Gah!"); let bitfield_int_ty = helpers::integer_type(ctx, bitfield_ty_layout)
.expect( "Should already have verified that the bitfield is \
representable as an int",
);
let offset = self.offset_into_unit(); let width = self.width() as u8; let prefix = ctx.trait_prefix();
/// 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<'a> FieldCodegen<'a> for BitfieldUnit { type Extra = ();
// 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. letmut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT;
letmut unit_visibility = visibility_kind; for bf inself.bitfields() { // Codegen not allowed for anonymous bitfields if bf.name().is_none() { continue;
}
if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT &&
!ctx.options().rust_features().larger_arrays
{ continue;
}
// 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);
// Don't output classes with template parameters that aren't types, and // also don't output template specializations, neither total or partial. ifself.has_non_type_template_params() { return;
}
let ty = item.expect_type(); let layout = ty.layout(ctx); letmut 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, &()); letmut fields = vec![]; let visibility = item
.annotations()
.visibility_kind()
.unwrap_or(ctx.options().default_visibility); letmut struct_layout = StructLayoutTracker::new(
ctx, self,
ty,
&canonical_name,
visibility,
packed,
);
if !is_opaque { if item.has_vtable_ptr(ctx) { let vtable = Vtable::new(item.id(), self);
vtable.codegen(ctx, result, item);
let vtable_type = vtable
.try_to_rust_ty(ctx, &())
.expect("vtable to Rust type conversion is infallible")
.to_ptr(true);
letmut methods = vec![]; if !is_opaque { let struct_accessor_kind = item
.annotations()
.accessor_kind()
.unwrap_or(FieldAccessorKind::None); for field inself.fields() {
field.codegen(
ctx,
visibility,
struct_accessor_kind, self,
item,
result,
&mut struct_layout,
&mut fields,
&mut methods,
(),
);
} // Check whether an explicit padding field is needed // at the end. iflet 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();
letmut explicit_align = None;
// C++ requires every struct to be addressable, so what C++ compilers do // is making the struct 1-byte sized. // // This is apparently not the case for C, see: // https://github.com/rust-lang/rust-bindgen/issues/551 // // Just get the layout, and assume C++ if not. // // NOTE: This check is conveniently here to avoid the dummy fields we // may add for unused template parameters. if !forward_decl && zero_sized { let has_address = if is_opaque { // Generate the address field if it's an opaque type and // couldn't determine the layout of the blob.
layout.is_none()
} else {
layout.map_or(true, |l| l.size != 0)
};
if has_address { let layout = Layout::new(1, 1); let ty = helpers::blob(ctx, Layout::new(1, 1));
struct_layout.saw_field_with_layout( "_address",
layout, /* offset = */ Some(0),
);
fields.push(quote! { pub _address: #ty,
});
}
}
if is_opaque { match layout {
Some(l) => {
explicit_align = Some(l.align);
let ty = helpers::blob(ctx, l);
fields.push(quote! { pub _bindgen_opaque_blob: #ty ,
});
}
None => {
warn!("Opaque type without layout! Expect dragons!");
}
}
} elseif !is_union && !zero_sized { iflet Some(padding_field) =
layout.and_then(|layout| struct_layout.pad_struct(layout))
{
fields.push(padding_field);
}
iflet Some(layout) = layout { if struct_layout.requires_explicit_align(layout) { if layout.align == 1 {
packed = true;
} else {
explicit_align = Some(layout.align); if !ctx.options().rust_features.repr_align { let ty = helpers::blob(
ctx,
Layout::new(0, layout.align),
);
fields.push(quote! { pub __bindgen_align: #ty ,
});
}
}
}
}
} elseif is_union && !forward_decl { // TODO(emilio): It'd be nice to unify this with the struct path // above somehow. let layout = layout.expect("Unable to get layout information?"); if struct_layout.requires_explicit_align(layout) {
explicit_align = Some(layout.align);
}
if !struct_layout.is_rust_union() { let ty = helpers::blob(ctx, layout);
fields.push(quote! { pub bindgen_union_field: #ty ,
})
}
}
if forward_decl {
fields.push(quote! {
_unused: [u8; 0],
});
}
letmut generic_param_names = vec![];
for (idx, ty) in item.used_template_params(ctx).iter().enumerate() { let param = ctx.resolve_type(*ty); let name = param.name().unwrap(); let ident = ctx.rust_ident(name);
generic_param_names.push(ident.clone());
let prefix = ctx.trait_prefix(); let field_name = ctx.rust_ident(format!("_phantom_{}", idx));
fields.push(quote! { pub#field_name : ::#prefix::marker::PhantomData<
::#prefix::cell::UnsafeCell<#ident>
> ,
});
}
let generics = if !generic_param_names.is_empty() { let generic_param_names = generic_param_names.clone();
quote! {
< #(#generic_param_names ),* >
}
} else {
quote! {}
};
// if a type has both a "packed" attribute and an "align(N)" attribute, then check if the // "packed" attr is redundant, and do not include it if so. if packed &&
!is_opaque &&
!(explicit_align.is_some() && self.already_packed(ctx).unwrap_or(false))
{ let n = layout.map_or(1, |l| l.align);
assert!(ctx.options().rust_features().repr_packed_n || n == 1); let packed_repr = if n == 1 { "packed".to_string()
} else {
format!("packed({})", n)
};
attributes.push(attributes::repr_list(&["C", &packed_repr]));
} else {
attributes.push(attributes::repr("C"));
}
if ctx.options().rust_features().repr_align { iflet Some(explicit) = explicit_align { // Ensure that the struct has the correct alignment even in // presence of alignas. let explicit = helpers::ast_ty::int_expr(explicit as i64);
attributes.push(quote! { #[repr(align(#explicit))]
});
}
}
let derivable_traits = derives_of_item(item, ctx, packed); if !derivable_traits.contains(DerivableTraits::DEBUG) {
needs_debug_impl = ctx.options().derive_debug &&
ctx.options().impl_debug &&
!ctx.no_debug_by_name(item) &&
!item.annotations().disallow_debug();
}
let is_rust_union = is_union && struct_layout.is_rust_union();
// The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives = ctx.options().all_callbacks(|cb| {
cb.add_derives(&DeriveInfo {
name: &canonical_name,
kind: if is_rust_union {
DeriveTypeKind::Union
} else {
DeriveTypeKind::Struct
},
})
}); // In most cases this will be a no-op, since custom_derives will be empty.
derives.extend(custom_derives.iter().map(|s| s.as_str()));
if !derives.is_empty() {
attributes.push(attributes::derives(&derives))
}
if item.must_use(ctx) {
attributes.push(attributes::must_use());
}
// 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 inself.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. ifself.found_unknown_attr() {
warn!( "Type {} has an unknown attribute that may affect layout",
canonical_ident
);
}
if all_template_params.is_empty() { if !is_opaque { for var inself.inner_vars() {
ctx.resolve_item(*var).codegen(ctx, result, &());
}
}
if ctx.options().layout_tests && !self.is_forward_declaration() { iflet Some(layout) = layout { let fn_name =
format!("bindgen_test_layout_{}", canonical_ident); let fn_name = ctx.rust_ident_raw(fn_name); let prefix = ctx.trait_prefix(); let size_of_expr = quote! {
::#prefix::mem::size_of::<#canonical_ident>()
}; let align_of_expr = quote! {
::#prefix::mem::align_of::<#canonical_ident>()
}; let size = layout.size; let align = layout.align;
let check_struct_align = if align >
ctx.target_pointer_size() &&
!ctx.options().rust_features().repr_align
{
None
} else {
Some(quote! {
assert_eq!(#align_of_expr, #align,
concat!("Alignment of ", stringify!(#canonical_ident)));
})
};
let should_skip_field_offset_checks = is_opaque;
let check_field_offset = if should_skip_field_offset_checks
{
vec![]
} else { self.fields()
.iter()
.filter_map(|field| match *field {
Field::DataMember(ref f) if f.name().is_some() => Some(f),
_ => None,
})
.flat_map(|field| { let name = field.name().unwrap();
field.offset().map(|offset| { let field_offset = offset / 8; let field_name = ctx.rust_ident(name);
quote! {
assert_eq!( unsafe {
::#prefix::ptr::addr_of!((*ptr).#field_name) as usize - ptr as usize
}, #field_offset,
concat!("Offset of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name))
);
}
})
})
.collect()
};
let uninit_decl = if !check_field_offset.is_empty() { // FIXME: When MSRV >= 1.59.0, we can use // > const PTR: *const #canonical_ident = ::#prefix::mem::MaybeUninit::uninit().as_ptr();
Some(quote! { // Use a shared MaybeUninit so that rustc with // opt-level=0 doesn't take too much stack space, // see #2218. const UNINIT: ::#prefix::mem::MaybeUninit<#canonical_ident> = ::#prefix::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr();
})
} else {
None
};
// NB: We can't use to_rust_ty here since for opaque types this tries to // use the specialization knowledge to generate a blob field. let ty_for_impl = quote! { #canonical_ident#generics
};
if needs_default_impl { let prefix = ctx.trait_prefix(); let body = if ctx.options().rust_features().maybe_uninit {
quote! { letmut s = ::#prefix::mem::MaybeUninit::<Self>::uninit(); unsafe {
::#prefix::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
} else {
quote! { unsafe { letmut s: Self = ::#prefix::mem::uninitialized();
::#prefix::ptr::write_bytes(&mut s, 0, 1);
s
}
}
}; // Note we use `ptr::write_bytes()` instead of `mem::zeroed()` because the latter does // not necessarily ensure padding bytes are zeroed. Some C libraries are sensitive to // non-zero padding bytes, especially when forwards/backwards compatability is // involved.
result.push(quote! { impl#generics Default for#ty_for_impl { fn default() -> Self { #body
}
}
});
}
if needs_debug_impl { let impl_ = impl_debug::gen_debug_impl(
ctx, self.fields(),
item, self.kind(),
);
// TODO(emilio): We could generate final stuff at least. ifself.is_virtual() { return; // FIXME
}
// First of all, output the actual function. let function_item = ctx.resolve_item(self.signature()); if !function_item.process_before_codegen(ctx, result) { return;
} let function = function_item.expect_function(); let times_seen = function.codegen(ctx, result, function_item); let times_seen = match times_seen {
Some(seen) => seen,
None => return,
}; let signature_item = ctx.resolve_item(function.signature()); letmut name = matchself.kind() {
MethodKind::Constructor => "new".into(),
MethodKind::Destructor => "destruct".into(),
_ => function.name().to_owned(),
};
let signature = match *signature_item.expect_type().kind() {
TypeKind::Function(ref sig) => sig,
_ => panic!("How in the world?"),
};
let supported_abi = signature.abi(ctx, Some(&*name)).is_ok(); if !supported_abi { return;
}
// Do not generate variadic methods, since rust does not allow // implementing them, and we don't do a good job at it anyway. if signature.is_variadic() { return;
}
if method_names.contains(&name) { letmut count = 1; letmut new_name;
// 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. ifself.is_constructor() {
args.remove(0);
ret = quote! { -> Self };
}
let block = ctx.wrap_unsafe_ops(quote! ( #(#stmts );*));
letmut attrs = vec![attributes::inline()];
if signature.must_use() &&
ctx.options().rust_features().must_use_function
{
attrs.push(attributes::must_use());
}
let name = ctx.rust_ident(&name);
methods.push(quote! { #(#attrs)* pubunsafefn#name ( #(#args ),* ) #ret { #block
}
});
}
}
/// A helper type that represents different enum variations. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pubenum EnumVariation { /// The code for this enum will use a Rust enum. Note that creating this in unsafe code /// (including FFI) with an invalid value will invoke undefined behaviour, whether or not /// its marked as non_exhaustive.
Rust { /// Indicates whether the generated struct should be `#[non_exhaustive]`
non_exhaustive: bool,
}, /// The code for this enum will use a newtype
NewType { /// Indicates whether the newtype will have bitwise operators
is_bitfield: bool, /// Indicates whether the variants will be represented as global constants
is_global: bool,
}, /// The code for this enum will use consts
Consts, /// The code for this enum will use a module containing consts
ModuleConsts,
}
/// Both the `Const` and `ModuleConsts` variants will cause this to return /// true. fn is_const(&self) -> bool {
matches!(*self, EnumVariation::Consts | EnumVariation::ModuleConsts)
}
}
impl<'a> EnumBuilder<'a> { /// Returns true if the builder is for a rustified enum. fn is_rust_enum(&self) -> bool {
matches!(*self, EnumBuilder::Rust { .. })
}
/// Create a new enum given an item builder, a canonical name, a name for /// the representation, and which variation it should be generated as. fn new(
name: &'a str, mut attrs: Vec<proc_macro2::TokenStream>,
repr: syn::Type,
enum_variation: EnumVariation,
has_typedef: bool,
) -> Self { let ident = Ident::new(name, Span::call_site());
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 = matchself.repr().map(|repr| ctx.resolve_type(repr)) {
Some(repr) if !ctx.options().translate_enum_integer_types &&
!variation.is_rust() =>
{
repr
}
repr => { // An enum's integer type is translated to a native Rust // integer type in 3 cases: // * the enum is Rustified and we need a translated type for // the repr attribute // * the representation couldn't be determined from the C source // * it was explicitly requested as a bindgen option
let kind = match repr {
Some(repr) => match *repr.canonical_type(ctx).kind() {
TypeKind::Int(int_kind) => int_kind,
_ => panic!("Unexpected type as enum repr"),
},
None => {
warn!( "Guessing type of enum! Forward declarations of enums \
shouldn't be legal!"
);
IntKind::Int
}
};
let signed = kind.is_signed(); let size = layout
.map(|l| l.size)
.or_else(|| kind.known_size())
.unwrap_or(0);
if item.must_use(ctx) {
attrs.push(attributes::must_use());
}
if !variation.is_const() { let packed = false; // Enums can't be packed in Rust. letmut 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,
); letmut derives: Vec<_> = derives.into(); for derive in item.annotations().derives().iter() { if !derives.contains(&derive.as_str()) {
derives.push(derive);
}
}
// The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives = ctx.options().all_callbacks(|cb| {
cb.add_derives(&DeriveInfo {
name: &name,
kind: DeriveTypeKind::Enum,
})
}); // In most cases this will be a no-op, since custom_derives will be empty.
derives.extend(custom_derives.iter().map(|s| s.as_str()));
attrs.push(attributes::derives(&derives));
}
fn add_constant(
ctx: &BindgenContext,
enum_: &Type, // Only to avoid recomputing every time.
enum_canonical_name: &Ident, // May be the same as "variant" if it's because the // enum is unnamed and we still haven't seen the // value.
variant_name: &Ident,
referenced_name: &Ident,
enum_rust_ty: syn::Type,
result: &mut CodegenResult<'_>,
) { let constant_name = if enum_.name().is_some() { if ctx.options().prepend_enum_name {
format!("{}_{}", enum_canonical_name, variant_name)
} else {
format!("{}", variant_name)
}
} else {
format!("{}", variant_name)
}; let constant_name = ctx.rust_ident(constant_name);
// A map where we keep a value -> variant relation. letmut 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). letmut constified_variants = VecDeque::new();
letmut iter = self.variants().iter().peekable(); whilelet Some(variant) =
iter.next().or_else(|| constified_variants.pop_front())
{ if variant.hidden() { continue;
}
if variant.force_constification() && iter.peek().is_some() {
constified_variants.push_back(variant); continue;
}
match seen_values.entry(variant.val()) {
Entry::Occupied(ref entry) => { if variation.is_rust() { let variant_name = ctx.rust_mangle(variant.name()); let mangled_name = if is_toplevel || enum_ty.name().is_some() {
variant_name
} else { let parent_name =
parent_canonical_name.as_ref().unwrap();
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();
let item = builder.build(ctx, enum_rust_ty, result);
result.push(item);
}
}
/// Enum for the default type of macro constants. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pubenum MacroTypeVariation { /// Use i32 or i64
Signed, /// Use u32 or u64
Unsigned,
}
impl fmt::Display for MacroTypeVariation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = matchself { Self::Signed => "signed", Self::Unsigned => "unsigned",
};
s.fmt(f)
}
}
impl std::str::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)] pubenum AliasVariation { /// Convert to regular Rust alias
TypeAlias, /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)]
NewType, /// Same as NewStruct but also impl Deref to be able to use the methods of the wrapped type
NewTypeDeref,
}
impl fmt::Display for AliasVariation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = matchself { Self::TypeAlias => "type_alias", Self::NewType => "new_type", Self::NewTypeDeref => "new_type_deref",
};
impl std::str::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)] pubenum NonCopyUnionStyle { /// Wrap members in a type generated by `bindgen`.
BindgenWrapper, /// Wrap members in [`::core::mem::ManuallyDrop`]. /// /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your /// MSRV is lower.
ManuallyDrop,
}
impl fmt::Display for NonCopyUnionStyle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = matchself { Self::BindgenWrapper => "bindgen_wrapper", Self::ManuallyDrop => "manually_drop",
};
impl std::str::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))
}
}
/// 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))
}
/// 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;
/// 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;
/// Infallible conversion to a Rust type, or an opaque blob with a best effort /// of correct size and alignment. /// /// Don't implement this directly. Instead implement `TryToRustTy` and /// `TryToOpaque`, and then leverage the blanket impl for this trait below. /// /// ### Fallible vs. Infallible Conversions to Rust Types /// /// When should one use this infallible `ToRustTyOrOpaque` trait versus the /// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait /// implementations that need to convert another thing into a Rust type or /// opaque blob in a nested manner should also use fallible trait methods and /// propagate failure up the stack. Only infallible functions and methods like /// CodeGenerator implementations should use the infallible /// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely /// we are to get a usable `Layout` even if we can't generate an equivalent Rust /// type for a C++ construct. pub(crate) trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { type Extra;
utils::build_path(item, ctx)
}
TypeKind::Opaque => self.try_to_opaque(ctx, item),
TypeKind::Pointer(inner) | TypeKind::Reference(inner) => { // Check that this type has the same size as the target's pointer type. let size = self.get_layout(ctx, item).size; if size != ctx.target_pointer_size() { return Err(Error::InvalidPointerSize {
ty_name: self.name().unwrap_or("unknown").into(),
ty_size: size,
ptr_size: ctx.target_pointer_size(),
});
}
let is_const = ctx.resolve_type(inner).is_const();
let inner =
inner.into_resolver().through_type_refs().resolve(ctx); let inner_ty = inner.expect_type();
let is_objc_pointer =
matches!(inner_ty.kind(), TypeKind::ObjCInterface(..));
// Regardless if we can properly represent the inner type, we // should always generate a proper pointer here, so use // infallible conversion of the inner type. let ty = inner
.to_rust_ty_or_opaque(ctx, &())
.with_implicit_template_params(ctx, inner);
// Avoid the first function pointer level, since it's already // represented in Rust. if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer
{
Ok(ty)
} else {
Ok(ty.to_ptr(is_const))
}
}
TypeKind::TypeParam => { let name = item.canonical_name(ctx); let ident = ctx.rust_ident(name);
Ok(syn::parse_quote! { #ident })
}
TypeKind::ObjCSel => Ok(syn::parse_quote! { objc::runtime::Sel }),
TypeKind::ObjCId => Ok(syn::parse_quote! { id }),
TypeKind::ObjCInterface(ref interface) => { let name = ctx.rust_ident(interface.name());
Ok(syn::parse_quote! { #name })
} ref u @ TypeKind::UnresolvedTypeRef(..) => {
unreachable!("Should have been resolved after parsing {:?}!", u)
}
}
}
}
impl TryToOpaque for TemplateInstantiation { type Extra = Item;
let def = self
.template_definition()
.into_resolver()
.through_type_refs()
.resolve(ctx);
letmut ty = quote! {}; let def_path = def.namespace_aware_canonical_path(ctx);
ty.append_separated(
def_path.into_iter().map(|p| ctx.rust_ident(p)),
quote!(::),
);
let def_params = def.self_template_params(ctx); if def_params.is_empty() { // This can happen if we generated an opaque type for a partial // template specialization, and we've hit an instantiation of // that partial specialization.
extra_assert!(def.is_opaque(ctx, &())); return Err(error::Error::InstantiationOfOpaqueType);
}
// TODO: If the definition type is a template class/struct // definition's member template definition, it could rely on // generic template parameters from its outer template // class/struct. When we emit bindings for it, it could require // *more* type arguments than we have here, and we will need to // reconstruct them somehow. We don't have any means of doing // that reconstruction at this time.
let template_args = self
.template_arguments()
.iter()
.zip(def_params.iter()) // Only pass type arguments for the type parameters that // the def uses.
.filter(|&(_, param)| ctx.uses_template_parameter(def.id(), *param))
.map(|(arg, _)| { let arg = arg.into_resolver().through_type_refs().resolve(ctx); let ty = arg
.try_to_rust_ty(ctx, &())?
.with_implicit_template_params(ctx, arg);
Ok(ty)
})
.collect::<error::Result<Vec<_>>>()?;
let is_internal = matches!(self.linkage(), Linkage::Internal);
let signature_item = ctx.resolve_item(self.signature()); let signature = signature_item.kind().expect_type().canonical_type(ctx); let signature = match *signature.kind() {
TypeKind::Function(ref sig) => sig,
_ => panic!("Signature kind is not a Function: {:?}", signature),
};
if is_internal { if !ctx.options().wrap_static_fns { // We cannot do anything with internal functions if we are not wrapping them so // just avoid generating anything for them. return None;
}
if signature.is_variadic() { // We cannot generate wrappers for variadic static functions so we avoid // generating any code for them.
variadic_fn_diagnostic(self.name(), item.location(), ctx); return None;
}
}
// Pure virtual methods have no actual symbol, so we can't generate // something meaningful for them. let is_dynamic_function = matchself.kind() {
FunctionKind::Method(ref method_kind) if method_kind.is_pure_virtual() =>
{ return None;
}
FunctionKind::Function => {
ctx.options().dynamic_library_name.is_some()
}
_ => false,
};
// Similar to static member variables in a class template, we can't // generate bindings to template functions, because the set of // instantiations is open ended and we have no way of knowing which // monomorphizations actually exist. if !item.all_template_params(ctx).is_empty() { return None;
}
let name = self.name(); letmut 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);
}
letmut attributes = vec![];
if ctx.options().rust_features().must_use_function { let must_use = signature.must_use() || { let ret_ty = signature
.return_type()
.into_resolver()
.through_type_refs()
.resolve(ctx);
ret_ty.must_use(ctx)
};
if must_use {
attributes.push(attributes::must_use());
}
}
let abi = match signature.abi(ctx, Some(name)) {
Err(err) => { if matches!(err, error::Error::UnsupportedAbi(_)) {
unsupported_abi_diagnostic(
name,
signature.is_variadic(),
item.location(),
ctx,
&err,
);
}
return None;
}
Ok(ClangAbi::Unknown(unknown_abi)) => {
panic!( "Invalid or unknown abi {:?} for function {:?} ({:?})",
unknown_abi, canonical_name, self
);
}
Ok(abi) => abi,
};
// Handle overloaded functions by giving each overload its own unique // suffix. let times_seen = result.overload_number(&canonical_name); if times_seen > 0 {
write!(&mut canonical_name, "{}", times_seen).unwrap();
}
// Unfortunately this can't piggyback on the `attributes` list because // the #[link(wasm_import_module)] needs to happen before the `extern // "C"` block. It doesn't get picked up properly otherwise let wasm_link_attribute =
ctx.options().wasm_import_module_name.as_ref().map(|name| {
quote! { #[link(wasm_import_module = #name)] }
});
let should_wrap =
is_internal && ctx.options().wrap_static_fns && !has_link_name_attr;
if should_wrap { let name = canonical_name.clone() + ctx.wrap_static_fns_suffix();
attributes.push(attributes::link_name::<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) = iflet 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);
#[cfg(feature = "experimental")] if ctx.options().emit_diagnostics { usecrate::diagnostics::{get_line, Diagnostic, Level, Slice};
letmut diag = Diagnostic::default();
diag.with_title(
format!( "Skipping {}function `{}` because the {}", if variadic { "variadic " } else { "" },
fn_name,
error
),
Level::Warn,
)
.add_annotation( "No code will be generated for this function.",
Level::Warn,
)
.add_annotation(
format!( "The configured Rust version is {}.",
ctx.options().rust_target
),
Level::Note,
);
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 { usecrate::diagnostics::{get_line, Diagnostic, Level, Slice};
letmut diag = Diagnostic::default();
diag.with_title(format!("Cannot generate wrapper for the static function `{}`.", fn_name), Level::Warn)
.add_annotation("The `--wrap-static-fns` feature does not support variadic functions.", Level::Note)
.add_annotation("No code will be generated for this function.", Level::Note);
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()));
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); letmut 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);
}
}
}
pub(crate) mod utils { usesuper::serialize::CSerialize; usesuper::{error, CodegenError, CodegenResult, ToRustTyOrOpaque}; usecrate::ir::context::BindgenContext; usecrate::ir::context::TypeId; usecrate::ir::function::{Abi, ClangAbi, FunctionSig}; usecrate::ir::item::{Item, ItemCanonicalPath}; usecrate::ir::ty::TypeKind; usecrate::{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;
if !context.options().input_headers.is_empty() { for header in &context.options().input_headers {
writeln!(code, "#include \"{}\"", header)?;
}
writeln!(code)?;
}
if !context.options().input_header_contents.is_empty() { for (name, contents) in &context.options().input_header_contents {
writeln!(code, "// {}\n{}", name, contents)?;
}
writeln!(code)?;
}
writeln!(code, "// Static wrappers\n")?;
for (id, wrap_as_variadic) in &result.items_to_serialize { let item = context.resolve_item(*id);
item.serialize(context, wrap_as_variadic, &mut vec![], &yle='color:red'>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;
}
letmut 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>,
) { let bitfield_unit_src = include_str!("./bitfield_unit.rs"); let bitfield_unit_src = if ctx.options().rust_features().min_const_fn {
Cow::Borrowed(bitfield_unit_src)
} else {
Cow::Owned(bitfield_unit_src.replace("const fn ", "fn "))
}; let bitfield_unit_type =
proc_macro2::TokenStream::from_str(&bitfield_unit_src).unwrap(); let bitfield_unit_type = quote!(#bitfield_unit_type);
let items = vec![bitfield_unit_type]; let old_items = mem::replace(result, items);
result.extend(old_items);
}
// If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. let const_fn = if ctx.options().rust_features().min_const_fn {
quote! { constfn }
} else {
quote! { fn }
};
// TODO(emilio): The fmt::Debug impl could be way nicer with // std::intrinsics::type_name, but... let union_field_decl = quote! { #[repr(C)] pubstruct __BindgenUnionField<T>(::#prefix::marker::PhantomData<T>);
};
let transmute =
ctx.wrap_unsafe_ops(quote!(::#prefix::mem::transmute(self)));
// 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 arg_item = ctx.resolve_item(ty); let arg_ty = arg_item.kind().expect_type();
// From the C90 standard[1]: // // A declaration of a parameter as "array of type" shall be // adjusted to "qualified pointer to type", where the type // qualifiers (if any) are those specified within the [ and ] of // the array type derivation. // // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html match *arg_ty.canonical_type(ctx).kind() {
TypeKind::Array(t, _) => { let stream = if ctx.options().array_pointers_in_arguments {
arg_ty.to_rust_ty_or_opaque(ctx, arg_item)
} else {
t.to_rust_ty_or_opaque(ctx, &())
};
stream.to_ptr(ctx.resolve_type(t).is_const())
}
TypeKind::Pointer(inner) => { let inner = ctx.resolve_item(inner); let inner_ty = inner.expect_type(); iflet 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, &()),
}
}
// 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 { returntrue;
}
// Working with &[u8] makes indexing simpler than with &str let canonical_name = canonical_name.as_bytes(); let mangled_name = mangled_name.as_bytes();
let (mangling_prefix, expect_suffix) = match call_conv {
Some(ClangAbi::Known(Abi::C)) | // None is the case for global variables
None => {
(b'_', false)
}
Some(ClangAbi::Known(Abi::Stdcall)) => (b'_', true),
Some(ClangAbi::Known(Abi::Fastcall)) => (b'@', true),
// This is something we don't recognize, stay on the safe side // by emitting the `#[link_name]` attribute
Some(_) => returnfalse,
};
// 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 { returnfalse;
}
// Return if the mangled name does not start with the prefix expected // for the given calling convention. if mangled_name[0] != mangling_prefix { returnfalse;
}
// Check that the mangled name contains the canonical name after the // prefix if &mangled_name[1..canonical_name.len() + 1] != canonical_name { returnfalse;
}
// 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 { returnfalse;
}
// 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)
{ returnfalse;
}
} elseif mangled_name.len() != canonical_name.len() + 1 { // If we don't expect a prefix but there is one, we need the // #[link_name] attribute returnfalse;
}
true
}
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.153Bemerkung:
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.