5473 lines
180 KiB
Rust
5473 lines
180 KiB
Rust
mod dyngen;
|
|
pub(crate) mod error;
|
|
|
|
mod helpers;
|
|
mod impl_debug;
|
|
mod impl_partialeq;
|
|
mod postprocessing;
|
|
mod serialize;
|
|
pub(crate) mod struct_layout;
|
|
|
|
#[cfg(test)]
|
|
#[allow(warnings)]
|
|
pub(crate) mod bitfield_unit;
|
|
#[cfg(all(test, target_endian = "little"))]
|
|
mod bitfield_unit_tests;
|
|
|
|
use self::dyngen::DynamicItems;
|
|
use self::helpers::attributes;
|
|
use self::struct_layout::StructLayoutTracker;
|
|
|
|
use super::BindgenOptions;
|
|
|
|
use crate::callbacks::{DeriveInfo, FieldInfo, TypeKind as DeriveTypeKind};
|
|
use crate::codegen::error::Error;
|
|
use crate::ir::analysis::{HasVtable, Sizedness};
|
|
use crate::ir::annotations::{
|
|
Annotations, FieldAccessorKind, FieldVisibilityKind,
|
|
};
|
|
use crate::ir::comp::{
|
|
Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData, FieldMethods,
|
|
Method, MethodKind,
|
|
};
|
|
use crate::ir::context::{BindgenContext, ItemId};
|
|
use crate::ir::derive::{
|
|
CanDerive, CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq,
|
|
CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd,
|
|
};
|
|
use crate::ir::dot;
|
|
use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
|
|
use crate::ir::function::{
|
|
ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
|
|
};
|
|
use crate::ir::int::IntKind;
|
|
use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
|
|
use crate::ir::item_kind::ItemKind;
|
|
use crate::ir::layout::Layout;
|
|
use crate::ir::module::Module;
|
|
use crate::ir::objc::{ObjCInterface, ObjCMethod};
|
|
use crate::ir::template::{
|
|
AsTemplateParam, TemplateInstantiation, TemplateParameters,
|
|
};
|
|
use crate::ir::ty::{Type, TypeKind};
|
|
use crate::ir::var::Var;
|
|
|
|
use proc_macro2::{self, Ident, Span};
|
|
use quote::TokenStreamExt;
|
|
|
|
use crate::{Entry, HashMap, HashSet};
|
|
use std::borrow::Cow;
|
|
use std::cell::Cell;
|
|
use std::collections::VecDeque;
|
|
use std::ffi::CStr;
|
|
use std::fmt::{self, Write};
|
|
use std::ops;
|
|
use std::str::{self, FromStr};
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum CodegenError {
|
|
Serialize { msg: String, loc: String },
|
|
Io(String),
|
|
}
|
|
|
|
impl From<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();
|
|
|
|
let all_template_params = item.all_template_params(ctx);
|
|
|
|
if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
|
|
derivable_traits |= DerivableTraits::COPY;
|
|
|
|
if ctx.options().rust_features().builtin_clone_impls ||
|
|
!all_template_params.is_empty()
|
|
{
|
|
// FIXME: This requires extra logic if you have a big array in a
|
|
// templated struct. The reason for this is that the magic:
|
|
// fn clone(&self) -> Self { *self }
|
|
// doesn't work for templates.
|
|
//
|
|
// It's not hard to fix though.
|
|
derivable_traits |= DerivableTraits::CLONE;
|
|
}
|
|
} else if packed {
|
|
// If the struct or union is packed, deriving from Copy is required for
|
|
// deriving from any other trait.
|
|
return derivable_traits;
|
|
}
|
|
|
|
if item.can_derive_debug(ctx) && !item.annotations().disallow_debug() {
|
|
derivable_traits |= DerivableTraits::DEBUG;
|
|
}
|
|
|
|
if item.can_derive_default(ctx) && !item.annotations().disallow_default() {
|
|
derivable_traits |= DerivableTraits::DEFAULT;
|
|
}
|
|
|
|
if item.can_derive_hash(ctx) {
|
|
derivable_traits |= DerivableTraits::HASH;
|
|
}
|
|
|
|
if item.can_derive_partialord(ctx) {
|
|
derivable_traits |= DerivableTraits::PARTIAL_ORD;
|
|
}
|
|
|
|
if item.can_derive_ord(ctx) {
|
|
derivable_traits |= DerivableTraits::ORD;
|
|
}
|
|
|
|
if item.can_derive_partialeq(ctx) {
|
|
derivable_traits |= DerivableTraits::PARTIAL_EQ;
|
|
}
|
|
|
|
if item.can_derive_eq(ctx) {
|
|
derivable_traits |= DerivableTraits::EQ;
|
|
}
|
|
|
|
derivable_traits
|
|
}
|
|
|
|
impl From<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)| {
|
|
Some(derive).filter(|_| derivable_traits.contains(flag))
|
|
})
|
|
.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<'a> ops::Deref for CodegenResult<'a> {
|
|
type Target = Vec<proc_macro2::TokenStream>;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.items
|
|
}
|
|
}
|
|
|
|
impl<'a> ops::DerefMut for CodegenResult<'a> {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.items
|
|
}
|
|
}
|
|
|
|
/// A trait to convert a rust type into a pointer, optionally const, to the same
|
|
/// type.
|
|
trait ToPtr {
|
|
fn to_ptr(self, is_const: bool) -> syn::Type;
|
|
}
|
|
|
|
impl ToPtr for syn::Type {
|
|
fn to_ptr(self, is_const: bool) -> syn::Type {
|
|
if is_const {
|
|
syn::parse_quote! { *const #self }
|
|
} else {
|
|
syn::parse_quote! { *mut #self }
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An extension trait for `syn::Type` that lets us append any implicit
|
|
/// template parameters that exist for some type, if necessary.
|
|
trait WithImplicitTemplateParams {
|
|
fn with_implicit_template_params(
|
|
self,
|
|
ctx: &BindgenContext,
|
|
item: &Item,
|
|
) -> Self;
|
|
}
|
|
|
|
impl WithImplicitTemplateParams for syn::Type {
|
|
fn with_implicit_template_params(
|
|
self,
|
|
ctx: &BindgenContext,
|
|
item: &Item,
|
|
) -> Self {
|
|
let item = item.id().into_resolver().through_type_refs().resolve(ctx);
|
|
|
|
let params = match *item.expect_type().kind() {
|
|
TypeKind::UnresolvedTypeRef(..) => {
|
|
unreachable!("already resolved unresolved type refs")
|
|
}
|
|
TypeKind::ResolvedTypeRef(..) => {
|
|
unreachable!("we resolved item through type refs")
|
|
}
|
|
// None of these types ever have implicit template parameters.
|
|
TypeKind::Void |
|
|
TypeKind::NullPtr |
|
|
TypeKind::Pointer(..) |
|
|
TypeKind::Reference(..) |
|
|
TypeKind::Int(..) |
|
|
TypeKind::Float(..) |
|
|
TypeKind::Complex(..) |
|
|
TypeKind::Array(..) |
|
|
TypeKind::TypeParam |
|
|
TypeKind::Opaque |
|
|
TypeKind::Function(..) |
|
|
TypeKind::Enum(..) |
|
|
TypeKind::ObjCId |
|
|
TypeKind::ObjCSel |
|
|
TypeKind::TemplateInstantiation(..) => None,
|
|
_ => {
|
|
let params = item.used_template_params(ctx);
|
|
if params.is_empty() {
|
|
None
|
|
} else {
|
|
Some(params.into_iter().map(|p| {
|
|
p.try_to_rust_ty(ctx, &()).expect(
|
|
"template params cannot fail to be a rust type",
|
|
)
|
|
}))
|
|
}
|
|
}
|
|
};
|
|
|
|
if let Some(params) = params {
|
|
syn::parse_quote! { #self<#(#params),*> }
|
|
} else {
|
|
self
|
|
}
|
|
}
|
|
}
|
|
|
|
trait CodeGenerator {
|
|
/// Extra information from the caller.
|
|
type Extra;
|
|
|
|
/// Extra information returned to the caller.
|
|
type Return;
|
|
|
|
fn codegen(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
result: &mut CodegenResult<'_>,
|
|
extra: &Self::Extra,
|
|
) -> Self::Return;
|
|
}
|
|
|
|
impl Item {
|
|
fn process_before_codegen(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
result: &mut CodegenResult,
|
|
) -> bool {
|
|
if !self.is_enabled_for_codegen(ctx) {
|
|
return false;
|
|
}
|
|
|
|
if self.is_blocklisted(ctx) || result.seen(self.id()) {
|
|
debug!(
|
|
"<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);
|
|
}
|
|
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() {
|
|
match *val {
|
|
VarType::Bool(val) => {
|
|
result.push(quote! {
|
|
#(#attrs)*
|
|
pub const #canonical_ident : #ty = #val ;
|
|
});
|
|
}
|
|
VarType::Int(val) => {
|
|
let int_kind = var_ty
|
|
.into_resolver()
|
|
.through_type_aliases()
|
|
.through_type_refs()
|
|
.resolve(ctx)
|
|
.expect_type()
|
|
.as_integer()
|
|
.unwrap();
|
|
let val = if int_kind.is_signed() {
|
|
helpers::ast_ty::int_expr(val)
|
|
} else {
|
|
helpers::ast_ty::uint_expr(val as _)
|
|
};
|
|
result.push(quote! {
|
|
#(#attrs)*
|
|
pub const #canonical_ident : #ty = #val ;
|
|
});
|
|
}
|
|
VarType::String(ref bytes) => {
|
|
let prefix = ctx.trait_prefix();
|
|
|
|
let options = ctx.options();
|
|
let rust_features = options.rust_features;
|
|
|
|
let mut cstr_bytes = bytes.clone();
|
|
cstr_bytes.push(0);
|
|
let len = proc_macro2::Literal::usize_unsuffixed(
|
|
cstr_bytes.len(),
|
|
);
|
|
|
|
// TODO: Here we ignore the type we just made up, probably
|
|
// we should refactor how the variable type and ty ID work.
|
|
let array_ty = quote! { [u8; #len] };
|
|
let cstr_ty = quote! { ::#prefix::ffi::CStr };
|
|
|
|
let bytes = proc_macro2::Literal::byte_string(&cstr_bytes);
|
|
|
|
if options.generate_cstr &&
|
|
rust_features.const_cstr &&
|
|
CStr::from_bytes_with_nul(&cstr_bytes).is_ok()
|
|
{
|
|
result.push(quote! {
|
|
#(#attrs)*
|
|
#[allow(unsafe_code)]
|
|
pub const #canonical_ident: &#cstr_ty = unsafe {
|
|
#cstr_ty::from_bytes_with_nul_unchecked(#bytes)
|
|
};
|
|
});
|
|
} else {
|
|
let lifetime = if rust_features.static_lifetime_elision
|
|
{
|
|
None
|
|
} else {
|
|
Some(quote! { 'static })
|
|
}
|
|
.into_iter();
|
|
|
|
result.push(quote! {
|
|
#(#attrs)*
|
|
pub const #canonical_ident: &#(#lifetime )*#array_ty = #bytes ;
|
|
});
|
|
}
|
|
}
|
|
VarType::Float(f) => {
|
|
if let Ok(expr) = helpers::ast_ty::float_expr(ctx, f) {
|
|
result.push(quote! {
|
|
#(#attrs)*
|
|
pub const #canonical_ident : #ty = #expr ;
|
|
});
|
|
}
|
|
}
|
|
VarType::Char(c) => {
|
|
result.push(quote! {
|
|
#(#attrs)*
|
|
pub const #canonical_ident : #ty = #c ;
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
// If necessary, apply a `#[link_name]` attribute
|
|
if let Some(link_name) = self.link_name() {
|
|
attrs.push(attributes::link_name::<false>(link_name));
|
|
} else {
|
|
let link_name =
|
|
self.mangled_name().unwrap_or_else(|| self.name());
|
|
if !utils::names_will_be_identical_after_mangling(
|
|
&canonical_name,
|
|
link_name,
|
|
None,
|
|
) {
|
|
attrs.push(attributes::link_name::<false>(link_name));
|
|
}
|
|
}
|
|
|
|
let maybe_mut = if self.is_const() {
|
|
quote! {}
|
|
} else {
|
|
quote! { mut }
|
|
};
|
|
|
|
let tokens = quote!(
|
|
extern "C" {
|
|
#(#attrs)*
|
|
pub static #maybe_mut #canonical_ident: #ty;
|
|
}
|
|
);
|
|
|
|
result.push(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CodeGenerator for Type {
|
|
type Extra = Item;
|
|
type Return = ();
|
|
|
|
fn codegen(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
result: &mut CodegenResult<'_>,
|
|
item: &Item,
|
|
) {
|
|
debug!("<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 `{}` ({}) does not match the target pointer size ({})",
|
|
spelling,
|
|
layout.size,
|
|
ctx.target_pointer_size(),
|
|
);
|
|
assert_eq!(
|
|
layout.align,
|
|
ctx.target_pointer_size(),
|
|
"Target platform requires `--no-size_t-is-usize`. The alignment of `{}` ({}) does not match the target pointer size ({})",
|
|
spelling,
|
|
layout.align,
|
|
ctx.target_pointer_size(),
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
|
|
let mut outer_params = item.used_template_params(ctx);
|
|
|
|
let is_opaque = item.is_opaque(ctx, &());
|
|
let inner_rust_type = if is_opaque {
|
|
outer_params = vec![];
|
|
self.to_opaque(ctx, item)
|
|
} else {
|
|
// Its possible that we have better layout information than
|
|
// the inner type does, so fall back to an opaque blob based
|
|
// on our layout if converting the inner item fails.
|
|
inner_item
|
|
.try_to_rust_ty_or_opaque(ctx, &())
|
|
.unwrap_or_else(|_| self.to_opaque(ctx, item))
|
|
.with_implicit_template_params(ctx, inner_item)
|
|
};
|
|
|
|
{
|
|
// FIXME(emilio): This is a workaround to avoid generating
|
|
// incorrect type aliases because of types that we haven't
|
|
// been able to resolve (because, eg, they depend on a
|
|
// template parameter).
|
|
//
|
|
// It's kind of a shame not generating them even when they
|
|
// could be referenced, but we already do the same for items
|
|
// with invalid template parameters, and at least this way
|
|
// they can be replaced, instead of generating plain invalid
|
|
// code.
|
|
let inner_canon_type =
|
|
inner_item.expect_type().canonical_type(ctx);
|
|
if inner_canon_type.is_invalid_type_param() {
|
|
warn!(
|
|
"Item contained invalid named type, skipping: \
|
|
{:?}, {:?}",
|
|
item, inner_item
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
let rust_name = ctx.rust_ident(&name);
|
|
|
|
let mut tokens = if let Some(comment) = item.comment(ctx) {
|
|
attributes::doc(comment)
|
|
} else {
|
|
quote! {}
|
|
};
|
|
|
|
let alias_style = if ctx.options().type_alias.matches(&name) {
|
|
AliasVariation::TypeAlias
|
|
} else if ctx.options().new_type_alias.matches(&name) {
|
|
AliasVariation::NewType
|
|
} else if ctx.options().new_type_alias_deref.matches(&name) {
|
|
AliasVariation::NewTypeDeref
|
|
} else {
|
|
ctx.options().default_alias_style
|
|
};
|
|
|
|
// We prefer using `pub use` over `pub type` because of:
|
|
// https://github.com/rust-lang/rust/issues/26264
|
|
if matches!(inner_rust_type, syn::Type::Path(_)) &&
|
|
outer_params.is_empty() &&
|
|
!is_opaque &&
|
|
alias_style == AliasVariation::TypeAlias &&
|
|
inner_item.expect_type().canonical_type(ctx).is_enum()
|
|
{
|
|
tokens.append_all(quote! {
|
|
pub use
|
|
});
|
|
let path = top_level_path(ctx, item);
|
|
tokens.append_separated(path, quote!(::));
|
|
tokens.append_all(quote! {
|
|
:: #inner_rust_type as #rust_name ;
|
|
});
|
|
result.push(tokens);
|
|
return;
|
|
}
|
|
|
|
tokens.append_all(match alias_style {
|
|
AliasVariation::TypeAlias => quote! {
|
|
pub type #rust_name
|
|
},
|
|
AliasVariation::NewType | AliasVariation::NewTypeDeref => {
|
|
assert!(
|
|
ctx.options().rust_features().repr_transparent,
|
|
"repr_transparent feature is required to use {:?}",
|
|
alias_style
|
|
);
|
|
|
|
let mut attributes =
|
|
vec![attributes::repr("transparent")];
|
|
let packed = false; // Types can't be packed in Rust.
|
|
let derivable_traits =
|
|
derives_of_item(item, ctx, packed);
|
|
if !derivable_traits.is_empty() {
|
|
let derives: Vec<_> = derivable_traits.into();
|
|
attributes.push(attributes::derives(&derives))
|
|
}
|
|
|
|
quote! {
|
|
#( #attributes )*
|
|
pub struct #rust_name
|
|
}
|
|
}
|
|
});
|
|
|
|
let params: Vec<_> = outer_params
|
|
.into_iter()
|
|
.filter_map(|p| p.as_template_param(ctx, &()))
|
|
.collect();
|
|
if params
|
|
.iter()
|
|
.any(|p| ctx.resolve_type(*p).is_invalid_type_param())
|
|
{
|
|
warn!(
|
|
"Item contained invalid template \
|
|
parameter: {:?}",
|
|
item
|
|
);
|
|
return;
|
|
}
|
|
let params: Vec<_> = params
|
|
.iter()
|
|
.map(|p| {
|
|
p.try_to_rust_ty(ctx, &()).expect(
|
|
"type parameters can always convert to rust ty OK",
|
|
)
|
|
})
|
|
.collect();
|
|
|
|
if !params.is_empty() {
|
|
tokens.append_all(quote! {
|
|
< #( #params ),* >
|
|
});
|
|
}
|
|
|
|
let access_spec =
|
|
access_specifier(ctx.options().default_visibility);
|
|
tokens.append_all(match alias_style {
|
|
AliasVariation::TypeAlias => quote! {
|
|
= #inner_rust_type ;
|
|
},
|
|
AliasVariation::NewType | AliasVariation::NewTypeDeref => {
|
|
quote! {
|
|
(#access_spec #inner_rust_type) ;
|
|
}
|
|
}
|
|
});
|
|
|
|
if alias_style == AliasVariation::NewTypeDeref {
|
|
let prefix = ctx.trait_prefix();
|
|
tokens.append_all(quote! {
|
|
impl ::#prefix::ops::Deref for #rust_name {
|
|
type Target = #inner_rust_type;
|
|
#[inline]
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
impl ::#prefix::ops::DerefMut for #rust_name {
|
|
#[inline]
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.0
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
result.push(tokens);
|
|
}
|
|
TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item),
|
|
TypeKind::ObjCId | TypeKind::ObjCSel => {
|
|
result.saw_objc();
|
|
}
|
|
TypeKind::ObjCInterface(ref interface) => {
|
|
interface.codegen(ctx, result, item)
|
|
}
|
|
ref u @ TypeKind::UnresolvedTypeRef(..) => {
|
|
unreachable!("Should have been resolved after parsing {:?}!", u)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Vtable<'a> {
|
|
item_id: ItemId,
|
|
/// A reference to the originating compound object.
|
|
#[allow(dead_code)]
|
|
comp_info: &'a CompInfo,
|
|
}
|
|
|
|
impl<'a> Vtable<'a> {
|
|
fn new(item_id: ItemId, comp_info: &'a CompInfo) -> Self {
|
|
Vtable { item_id, comp_info }
|
|
}
|
|
}
|
|
|
|
impl<'a> CodeGenerator for Vtable<'a> {
|
|
type Extra = Item;
|
|
type Return = ();
|
|
|
|
fn codegen(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
result: &mut CodegenResult<'_>,
|
|
item: &Item,
|
|
) {
|
|
assert_eq!(item.id(), self.item_id);
|
|
debug_assert!(item.is_enabled_for_codegen(ctx));
|
|
let name = ctx.rust_ident(self.canonical_name(ctx));
|
|
|
|
// For now, we will only generate vtables for classes that:
|
|
// - do not inherit from others (compilers merge VTable from primary parent class).
|
|
// - do not contain a virtual destructor (requires ordering; platforms generate different vtables).
|
|
if ctx.options().vtable_generation &&
|
|
self.comp_info.base_members().is_empty() &&
|
|
self.comp_info.destructor().is_none()
|
|
{
|
|
let class_ident = ctx.rust_ident(self.item_id.canonical_name(ctx));
|
|
|
|
let methods = self
|
|
.comp_info
|
|
.methods()
|
|
.iter()
|
|
.filter_map(|m| {
|
|
if !m.is_virtual() {
|
|
return None;
|
|
}
|
|
|
|
let function_item = ctx.resolve_item(m.signature());
|
|
let function = function_item.expect_function();
|
|
let signature_item = ctx.resolve_item(function.signature());
|
|
let signature = match signature_item.expect_type().kind() {
|
|
TypeKind::Function(ref sig) => sig,
|
|
_ => panic!("Function signature type mismatch"),
|
|
};
|
|
|
|
// FIXME: Is there a canonical name without the class prepended?
|
|
let function_name = function_item.canonical_name(ctx);
|
|
|
|
// FIXME: Need to account for overloading with times_seen (separately from regular function path).
|
|
let function_name = ctx.rust_ident(function_name);
|
|
let mut args = utils::fnsig_arguments(ctx, signature);
|
|
let ret = utils::fnsig_return_ty(ctx, signature);
|
|
|
|
args[0] = if m.is_const() {
|
|
quote! { this: *const #class_ident }
|
|
} else {
|
|
quote! { this: *mut #class_ident }
|
|
};
|
|
|
|
Some(quote! {
|
|
pub #function_name : unsafe extern "C" fn( #( #args ),* ) #ret
|
|
})
|
|
})
|
|
.collect::<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<'a> ItemCanonicalName for Vtable<'a> {
|
|
fn canonical_name(&self, ctx: &BindgenContext) -> String {
|
|
format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx))
|
|
}
|
|
}
|
|
|
|
impl<'a> TryToRustTy for Vtable<'a> {
|
|
type Extra = ();
|
|
|
|
fn try_to_rust_ty(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
_: &(),
|
|
) -> error::Result<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;
|
|
}
|
|
|
|
// If there are any unbound type parameters, then we can't generate a
|
|
// layout test because we aren't dealing with a concrete type with a
|
|
// concrete size and alignment.
|
|
if ctx.uses_any_template_parameters(item.id()) {
|
|
return;
|
|
}
|
|
|
|
let layout = item.kind().expect_type().layout(ctx);
|
|
|
|
if let Some(layout) = layout {
|
|
let size = layout.size;
|
|
let align = layout.align;
|
|
|
|
let name = item.full_disambiguated_name(ctx);
|
|
let mut fn_name =
|
|
format!("__bindgen_test_layout_{}_instantiation", name);
|
|
let times_seen = result.overload_number(&fn_name);
|
|
if times_seen > 0 {
|
|
write!(&mut fn_name, "_{}", times_seen).unwrap();
|
|
}
|
|
|
|
let fn_name = ctx.rust_ident_raw(fn_name);
|
|
|
|
let prefix = ctx.trait_prefix();
|
|
let ident = item.to_rust_ty_or_opaque(ctx, &());
|
|
let size_of_expr = quote! {
|
|
::#prefix::mem::size_of::<#ident>()
|
|
};
|
|
let align_of_expr = quote! {
|
|
::#prefix::mem::align_of::<#ident>()
|
|
};
|
|
|
|
let item = quote! {
|
|
#[test]
|
|
fn #fn_name() {
|
|
assert_eq!(#size_of_expr, #size,
|
|
concat!("Size of template specialization: ",
|
|
stringify!(#ident)));
|
|
assert_eq!(#align_of_expr, #align,
|
|
concat!("Alignment of template specialization: ",
|
|
stringify!(#ident)));
|
|
}
|
|
};
|
|
|
|
result.push(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Trait for implementing the code generation of a struct or union field.
|
|
trait FieldCodegen<'a> {
|
|
type Extra;
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
fn codegen<F, M>(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
visibility_kind: FieldVisibilityKind,
|
|
accessor_kind: FieldAccessorKind,
|
|
parent: &CompInfo,
|
|
parent_item: &Item,
|
|
result: &mut CodegenResult,
|
|
struct_layout: &mut StructLayoutTracker,
|
|
fields: &mut F,
|
|
methods: &mut M,
|
|
extra: Self::Extra,
|
|
) where
|
|
F: Extend<proc_macro2::TokenStream>,
|
|
M: Extend<proc_macro2::TokenStream>;
|
|
}
|
|
|
|
impl<'a> FieldCodegen<'a> for Field {
|
|
type Extra = ();
|
|
|
|
fn codegen<F, M>(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
visibility_kind: FieldVisibilityKind,
|
|
accessor_kind: FieldAccessorKind,
|
|
parent: &CompInfo,
|
|
parent_item: &Item,
|
|
result: &mut CodegenResult,
|
|
struct_layout: &mut StructLayoutTracker,
|
|
fields: &mut F,
|
|
methods: &mut M,
|
|
_: (),
|
|
) where
|
|
F: Extend<proc_macro2::TokenStream>,
|
|
M: Extend<proc_macro2::TokenStream>,
|
|
{
|
|
match *self {
|
|
Field::DataMember(ref data) => {
|
|
data.codegen(
|
|
ctx,
|
|
visibility_kind,
|
|
accessor_kind,
|
|
parent,
|
|
parent_item,
|
|
result,
|
|
struct_layout,
|
|
fields,
|
|
methods,
|
|
(),
|
|
);
|
|
}
|
|
Field::Bitfields(ref unit) => {
|
|
unit.codegen(
|
|
ctx,
|
|
visibility_kind,
|
|
accessor_kind,
|
|
parent,
|
|
parent_item,
|
|
result,
|
|
struct_layout,
|
|
fields,
|
|
methods,
|
|
(),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn wrap_union_field_if_needed(
|
|
ctx: &BindgenContext,
|
|
struct_layout: &StructLayoutTracker,
|
|
ty: syn::Type,
|
|
result: &mut CodegenResult,
|
|
) -> syn::Type {
|
|
if struct_layout.is_rust_union() {
|
|
if struct_layout.can_copy_union_fields() {
|
|
ty
|
|
} else {
|
|
let prefix = ctx.trait_prefix();
|
|
syn::parse_quote! { ::#prefix::mem::ManuallyDrop<#ty> }
|
|
}
|
|
} else {
|
|
result.saw_bindgen_union();
|
|
if ctx.options().enable_cxx_namespaces {
|
|
syn::parse_quote! { root::__BindgenUnionField<#ty> }
|
|
} else {
|
|
syn::parse_quote! { __BindgenUnionField<#ty> }
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> FieldCodegen<'a> for FieldData {
|
|
type Extra = ();
|
|
|
|
fn codegen<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)
|
|
} else if let Some(item) = field_ty.is_incomplete_array(ctx) {
|
|
result.saw_incomplete_array();
|
|
|
|
let inner = item.to_rust_ty_or_opaque(ctx, &());
|
|
|
|
if ctx.options().enable_cxx_namespaces {
|
|
syn::parse_quote! { root::__IncompleteArrayField<#inner> }
|
|
} else {
|
|
syn::parse_quote! { __IncompleteArrayField<#inner> }
|
|
}
|
|
} else {
|
|
ty
|
|
};
|
|
|
|
let mut field = quote! {};
|
|
if ctx.options().generate_comments {
|
|
if let Some(raw_comment) = self.comment() {
|
|
let comment = ctx.options().process_comment(raw_comment);
|
|
field = attributes::doc(comment);
|
|
}
|
|
}
|
|
|
|
let field_name = self
|
|
.name()
|
|
.map(|name| ctx.rust_mangle(name).into_owned())
|
|
.expect("Each field should have a name in codegen!");
|
|
let field_name = field_name.as_str();
|
|
let field_ident = ctx.rust_ident_raw(field_name);
|
|
|
|
if let Some(padding_field) =
|
|
struct_layout.saw_field(field_name, field_ty, self.offset())
|
|
{
|
|
fields.extend(Some(padding_field));
|
|
}
|
|
|
|
let visibility = compute_visibility(
|
|
ctx,
|
|
self.is_public(),
|
|
ctx.options().last_callback(|cb| {
|
|
cb.field_visibility(FieldInfo {
|
|
type_name: &parent_item.canonical_name(ctx),
|
|
field_name,
|
|
})
|
|
}),
|
|
self.annotations(),
|
|
parent_visibility_kind,
|
|
);
|
|
let accessor_kind =
|
|
self.annotations().accessor_kind().unwrap_or(accessor_kind);
|
|
|
|
match visibility {
|
|
FieldVisibilityKind::Private => {
|
|
field.append_all(quote! {
|
|
#field_ident : #ty ,
|
|
});
|
|
}
|
|
FieldVisibilityKind::PublicCrate => {
|
|
field.append_all(quote! {
|
|
pub(crate) #field_ident : #ty ,
|
|
});
|
|
}
|
|
FieldVisibilityKind::Public => {
|
|
field.append_all(quote! {
|
|
pub #field_ident : #ty ,
|
|
});
|
|
}
|
|
}
|
|
|
|
fields.extend(Some(field));
|
|
|
|
// TODO: Factor the following code out, please!
|
|
if accessor_kind == FieldAccessorKind::None {
|
|
return;
|
|
}
|
|
|
|
let getter_name = ctx.rust_ident_raw(format!("get_{}", field_name));
|
|
let mutable_getter_name =
|
|
ctx.rust_ident_raw(format!("get_{}_mut", field_name));
|
|
|
|
methods.extend(Some(match accessor_kind {
|
|
FieldAccessorKind::None => unreachable!(),
|
|
FieldAccessorKind::Regular => {
|
|
quote! {
|
|
#[inline]
|
|
pub fn #getter_name(&self) -> & #ty {
|
|
&self.#field_ident
|
|
}
|
|
|
|
#[inline]
|
|
pub fn #mutable_getter_name(&mut self) -> &mut #ty {
|
|
&mut self.#field_ident
|
|
}
|
|
}
|
|
}
|
|
FieldAccessorKind::Unsafe => {
|
|
quote! {
|
|
#[inline]
|
|
pub unsafe fn #getter_name(&self) -> & #ty {
|
|
&self.#field_ident
|
|
}
|
|
|
|
#[inline]
|
|
pub unsafe fn #mutable_getter_name(&mut self) -> &mut #ty {
|
|
&mut self.#field_ident
|
|
}
|
|
}
|
|
}
|
|
FieldAccessorKind::Immutable => {
|
|
quote! {
|
|
#[inline]
|
|
pub fn #getter_name(&self) -> & #ty {
|
|
&self.#field_ident
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
|
|
impl BitfieldUnit {
|
|
/// Get the constructor name for this bitfield unit.
|
|
fn ctor_name(&self) -> proc_macro2::TokenStream {
|
|
let ctor_name = Ident::new(
|
|
&format!("new_bitfield_{}", self.nth()),
|
|
Span::call_site(),
|
|
);
|
|
quote! {
|
|
#ctor_name
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Bitfield {
|
|
/// Extend an under construction bitfield unit constructor with this
|
|
/// bitfield. This sets the relevant bits on the `__bindgen_bitfield_unit`
|
|
/// variable that's being constructed.
|
|
fn extend_ctor_impl(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
param_name: proc_macro2::TokenStream,
|
|
mut ctor_impl: proc_macro2::TokenStream,
|
|
) -> proc_macro2::TokenStream {
|
|
let bitfield_ty = ctx.resolve_type(self.ty());
|
|
let bitfield_ty_layout = bitfield_ty
|
|
.layout(ctx)
|
|
.expect("Bitfield without layout? Gah!");
|
|
let bitfield_int_ty = helpers::integer_type(ctx, bitfield_ty_layout)
|
|
.expect(
|
|
"Should already have verified that the bitfield is \
|
|
representable as an int",
|
|
);
|
|
|
|
let offset = self.offset_into_unit();
|
|
let width = self.width() as u8;
|
|
let prefix = ctx.trait_prefix();
|
|
|
|
ctor_impl.append_all(quote! {
|
|
__bindgen_bitfield_unit.set(
|
|
#offset,
|
|
#width,
|
|
{
|
|
let #param_name: #bitfield_int_ty = unsafe {
|
|
::#prefix::mem::transmute(#param_name)
|
|
};
|
|
#param_name as u64
|
|
}
|
|
);
|
|
});
|
|
|
|
ctor_impl
|
|
}
|
|
}
|
|
|
|
fn access_specifier(
|
|
visibility: FieldVisibilityKind,
|
|
) -> proc_macro2::TokenStream {
|
|
match visibility {
|
|
FieldVisibilityKind::Private => quote! {},
|
|
FieldVisibilityKind::PublicCrate => quote! { pub(crate) },
|
|
FieldVisibilityKind::Public => quote! { pub },
|
|
}
|
|
}
|
|
|
|
/// Compute a fields or structs visibility based on multiple conditions.
|
|
/// 1. If the element was declared public, and we respect such CXX accesses specs
|
|
/// (context option) => By default Public, but this can be overruled by an `annotation`.
|
|
///
|
|
/// 2. If the element was declared private, and we respect such CXX accesses specs
|
|
/// (context option) => By default Private, but this can be overruled by an `annotation`.
|
|
///
|
|
/// 3. If we do not respect visibility modifiers, the result depends on the `annotation`,
|
|
/// if any, or the passed `default_kind`.
|
|
///
|
|
fn compute_visibility(
|
|
ctx: &BindgenContext,
|
|
is_declared_public: bool,
|
|
callback_override: Option<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 = ();
|
|
|
|
fn codegen<F, M>(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
visibility_kind: FieldVisibilityKind,
|
|
accessor_kind: FieldAccessorKind,
|
|
parent: &CompInfo,
|
|
parent_item: &Item,
|
|
result: &mut CodegenResult,
|
|
struct_layout: &mut StructLayoutTracker,
|
|
fields: &mut F,
|
|
methods: &mut M,
|
|
_: (),
|
|
) where
|
|
F: Extend<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 align_field_name = format!("_bitfield_align_{}", self.nth());
|
|
let align_field_ident = ctx.rust_ident(align_field_name);
|
|
let align_ty = match self.layout().align {
|
|
n if n >= 8 => quote! { u64 },
|
|
4 => quote! { u32 },
|
|
2 => quote! { u16 },
|
|
_ => quote! { u8 },
|
|
};
|
|
let access_spec = access_specifier(visibility_kind);
|
|
let align_field = quote! {
|
|
#access_spec #align_field_ident: [#align_ty; 0],
|
|
};
|
|
fields.extend(Some(align_field));
|
|
}
|
|
|
|
let unit_field_name = format!("_bitfield_{}", self.nth());
|
|
let unit_field_ident = ctx.rust_ident(&unit_field_name);
|
|
|
|
let ctor_name = self.ctor_name();
|
|
let mut ctor_params = vec![];
|
|
let mut ctor_impl = quote! {};
|
|
|
|
// We cannot generate any constructor if the underlying storage can't
|
|
// implement AsRef<[u8]> / AsMut<[u8]> / etc, or can't derive Default.
|
|
//
|
|
// We don't check `larger_arrays` here because Default does still have
|
|
// the 32 items limitation.
|
|
let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT;
|
|
|
|
let mut unit_visibility = visibility_kind;
|
|
for bf in self.bitfields() {
|
|
// Codegen not allowed for anonymous bitfields
|
|
if bf.name().is_none() {
|
|
continue;
|
|
}
|
|
|
|
if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT &&
|
|
!ctx.options().rust_features().larger_arrays
|
|
{
|
|
continue;
|
|
}
|
|
|
|
let mut bitfield_representable_as_int = true;
|
|
let mut bitfield_visibility = visibility_kind;
|
|
bf.codegen(
|
|
ctx,
|
|
visibility_kind,
|
|
accessor_kind,
|
|
parent,
|
|
parent_item,
|
|
result,
|
|
struct_layout,
|
|
fields,
|
|
methods,
|
|
(
|
|
&unit_field_name,
|
|
&mut bitfield_representable_as_int,
|
|
&mut bitfield_visibility,
|
|
),
|
|
);
|
|
if bitfield_visibility < unit_visibility {
|
|
unit_visibility = bitfield_visibility;
|
|
}
|
|
|
|
// Generating a constructor requires the bitfield to be representable as an integer.
|
|
if !bitfield_representable_as_int {
|
|
generate_ctor = false;
|
|
continue;
|
|
}
|
|
|
|
let param_name = bitfield_getter_name(ctx, bf);
|
|
let bitfield_ty_item = ctx.resolve_item(bf.ty());
|
|
let bitfield_ty = bitfield_ty_item.expect_type();
|
|
let bitfield_ty =
|
|
bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
|
|
|
|
ctor_params.push(quote! {
|
|
#param_name : #bitfield_ty
|
|
});
|
|
ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl);
|
|
}
|
|
|
|
let access_spec = access_specifier(unit_visibility);
|
|
|
|
let field = quote! {
|
|
#access_spec #unit_field_ident : #field_ty ,
|
|
};
|
|
fields.extend(Some(field));
|
|
|
|
if generate_ctor {
|
|
methods.extend(Some(quote! {
|
|
#[inline]
|
|
#access_spec fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty {
|
|
let mut __bindgen_bitfield_unit: #unit_field_ty = Default::default();
|
|
#ctor_impl
|
|
__bindgen_bitfield_unit
|
|
}
|
|
}));
|
|
}
|
|
|
|
struct_layout.saw_bitfield_unit(layout);
|
|
}
|
|
}
|
|
|
|
fn bitfield_getter_name(
|
|
ctx: &BindgenContext,
|
|
bitfield: &Bitfield,
|
|
) -> proc_macro2::TokenStream {
|
|
let name = bitfield.getter_name();
|
|
let name = ctx.rust_ident_raw(name);
|
|
quote! { #name }
|
|
}
|
|
|
|
fn bitfield_setter_name(
|
|
ctx: &BindgenContext,
|
|
bitfield: &Bitfield,
|
|
) -> proc_macro2::TokenStream {
|
|
let setter = bitfield.setter_name();
|
|
let setter = ctx.rust_ident_raw(setter);
|
|
quote! { #setter }
|
|
}
|
|
|
|
impl<'a> FieldCodegen<'a> for Bitfield {
|
|
type Extra = (&'a str, &'a mut bool, &'a mut FieldVisibilityKind);
|
|
|
|
fn codegen<F, M>(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
visibility_kind: FieldVisibilityKind,
|
|
_accessor_kind: FieldAccessorKind,
|
|
parent: &CompInfo,
|
|
parent_item: &Item,
|
|
_result: &mut CodegenResult,
|
|
struct_layout: &mut StructLayoutTracker,
|
|
_fields: &mut F,
|
|
methods: &mut M,
|
|
(unit_field_name, bitfield_representable_as_int, bitfield_visibility): (
|
|
&'a str,
|
|
&mut bool,
|
|
&'a mut FieldVisibilityKind,
|
|
),
|
|
) where
|
|
F: Extend<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 unit_field_ident = Ident::new(unit_field_name, Span::call_site());
|
|
|
|
let bitfield_ty_item = ctx.resolve_item(self.ty());
|
|
let bitfield_ty = bitfield_ty_item.expect_type();
|
|
|
|
let bitfield_ty_layout = bitfield_ty
|
|
.layout(ctx)
|
|
.expect("Bitfield without layout? Gah!");
|
|
let bitfield_int_ty =
|
|
match helpers::integer_type(ctx, bitfield_ty_layout) {
|
|
Some(int_ty) => {
|
|
*bitfield_representable_as_int = true;
|
|
int_ty
|
|
}
|
|
None => {
|
|
*bitfield_representable_as_int = false;
|
|
return;
|
|
}
|
|
};
|
|
|
|
let bitfield_ty =
|
|
bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
|
|
|
|
let offset = self.offset_into_unit();
|
|
let width = self.width() as u8;
|
|
|
|
let override_visibility = self.name().and_then(|field_name| {
|
|
ctx.options().last_callback(|cb| {
|
|
cb.field_visibility(FieldInfo {
|
|
type_name: &parent_item.canonical_name(ctx),
|
|
field_name,
|
|
})
|
|
})
|
|
});
|
|
*bitfield_visibility = compute_visibility(
|
|
ctx,
|
|
self.is_public(),
|
|
override_visibility,
|
|
self.annotations(),
|
|
visibility_kind,
|
|
);
|
|
let access_spec = access_specifier(*bitfield_visibility);
|
|
|
|
if parent.is_union() && !struct_layout.is_rust_union() {
|
|
methods.extend(Some(quote! {
|
|
#[inline]
|
|
#access_spec fn #getter_name(&self) -> #bitfield_ty {
|
|
unsafe {
|
|
::#prefix::mem::transmute(
|
|
self.#unit_field_ident.as_ref().get(#offset, #width)
|
|
as #bitfield_int_ty
|
|
)
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
#access_spec fn #setter_name(&mut self, val: #bitfield_ty) {
|
|
unsafe {
|
|
let val: #bitfield_int_ty = ::#prefix::mem::transmute(val);
|
|
self.#unit_field_ident.as_mut().set(
|
|
#offset,
|
|
#width,
|
|
val as u64
|
|
)
|
|
}
|
|
}
|
|
}));
|
|
} else {
|
|
methods.extend(Some(quote! {
|
|
#[inline]
|
|
#access_spec fn #getter_name(&self) -> #bitfield_ty {
|
|
unsafe {
|
|
::#prefix::mem::transmute(
|
|
self.#unit_field_ident.get(#offset, #width)
|
|
as #bitfield_int_ty
|
|
)
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
#access_spec fn #setter_name(&mut self, val: #bitfield_ty) {
|
|
unsafe {
|
|
let val: #bitfield_int_ty = ::#prefix::mem::transmute(val);
|
|
self.#unit_field_ident.set(
|
|
#offset,
|
|
#width,
|
|
val as u64
|
|
)
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CodeGenerator for CompInfo {
|
|
type Extra = Item;
|
|
type Return = ();
|
|
|
|
fn codegen(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
result: &mut CodegenResult<'_>,
|
|
item: &Item,
|
|
) {
|
|
debug!("<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,
|
|
);
|
|
|
|
if !is_opaque {
|
|
if item.has_vtable_ptr(ctx) {
|
|
let vtable = Vtable::new(item.id(), self);
|
|
vtable.codegen(ctx, result, item);
|
|
|
|
let vtable_type = vtable
|
|
.try_to_rust_ty(ctx, &())
|
|
.expect("vtable to Rust type conversion is infallible")
|
|
.to_ptr(true);
|
|
|
|
fields.push(quote! {
|
|
pub vtable_: #vtable_type ,
|
|
});
|
|
|
|
struct_layout.saw_vtable();
|
|
}
|
|
|
|
for base in self.base_members() {
|
|
if !base.requires_storage(ctx) {
|
|
continue;
|
|
}
|
|
|
|
let inner_item = ctx.resolve_item(base.ty);
|
|
let inner = inner_item
|
|
.to_rust_ty_or_opaque(ctx, &())
|
|
.with_implicit_template_params(ctx, inner_item);
|
|
let field_name = ctx.rust_ident(&base.field_name);
|
|
|
|
struct_layout.saw_base(inner_item.expect_type());
|
|
|
|
let visibility = match (
|
|
base.is_public(),
|
|
ctx.options().respect_cxx_access_specs,
|
|
) {
|
|
(true, true) => FieldVisibilityKind::Public,
|
|
(false, true) => FieldVisibilityKind::Private,
|
|
_ => ctx.options().default_visibility,
|
|
};
|
|
|
|
let access_spec = access_specifier(visibility);
|
|
fields.push(quote! {
|
|
#access_spec #field_name: #inner,
|
|
});
|
|
}
|
|
}
|
|
|
|
let mut methods = vec![];
|
|
if !is_opaque {
|
|
let struct_accessor_kind = item
|
|
.annotations()
|
|
.accessor_kind()
|
|
.unwrap_or(FieldAccessorKind::None);
|
|
for field in self.fields() {
|
|
field.codegen(
|
|
ctx,
|
|
visibility,
|
|
struct_accessor_kind,
|
|
self,
|
|
item,
|
|
result,
|
|
&mut struct_layout,
|
|
&mut fields,
|
|
&mut methods,
|
|
(),
|
|
);
|
|
}
|
|
// Check whether an explicit padding field is needed
|
|
// at the end.
|
|
if let Some(comp_layout) = layout {
|
|
fields.extend(
|
|
struct_layout
|
|
.add_tail_padding(&canonical_name, comp_layout),
|
|
);
|
|
}
|
|
}
|
|
|
|
if is_opaque {
|
|
// Opaque item should not have generated methods, fields.
|
|
debug_assert!(fields.is_empty());
|
|
debug_assert!(methods.is_empty());
|
|
}
|
|
|
|
let is_union = self.kind() == CompKind::Union;
|
|
let layout = item.kind().expect_type().layout(ctx);
|
|
let zero_sized = item.is_zero_sized(ctx);
|
|
let forward_decl = self.is_forward_declaration();
|
|
|
|
let mut explicit_align = None;
|
|
|
|
// C++ requires every struct to be addressable, so what C++ compilers do
|
|
// is making the struct 1-byte sized.
|
|
//
|
|
// This is apparently not the case for C, see:
|
|
// https://github.com/rust-lang/rust-bindgen/issues/551
|
|
//
|
|
// Just get the layout, and assume C++ if not.
|
|
//
|
|
// NOTE: This check is conveniently here to avoid the dummy fields we
|
|
// may add for unused template parameters.
|
|
if !forward_decl && zero_sized {
|
|
let has_address = if is_opaque {
|
|
// Generate the address field if it's an opaque type and
|
|
// couldn't determine the layout of the blob.
|
|
layout.is_none()
|
|
} else {
|
|
layout.map_or(true, |l| l.size != 0)
|
|
};
|
|
|
|
if has_address {
|
|
let layout = Layout::new(1, 1);
|
|
let ty = helpers::blob(ctx, Layout::new(1, 1));
|
|
struct_layout.saw_field_with_layout(
|
|
"_address",
|
|
layout,
|
|
/* offset = */ Some(0),
|
|
);
|
|
fields.push(quote! {
|
|
pub _address: #ty,
|
|
});
|
|
}
|
|
}
|
|
|
|
if is_opaque {
|
|
match layout {
|
|
Some(l) => {
|
|
explicit_align = Some(l.align);
|
|
|
|
let ty = helpers::blob(ctx, l);
|
|
fields.push(quote! {
|
|
pub _bindgen_opaque_blob: #ty ,
|
|
});
|
|
}
|
|
None => {
|
|
warn!("Opaque type without layout! Expect dragons!");
|
|
}
|
|
}
|
|
} else if !is_union && !zero_sized {
|
|
if let Some(padding_field) =
|
|
layout.and_then(|layout| struct_layout.pad_struct(layout))
|
|
{
|
|
fields.push(padding_field);
|
|
}
|
|
|
|
if let Some(layout) = layout {
|
|
if struct_layout.requires_explicit_align(layout) {
|
|
if layout.align == 1 {
|
|
packed = true;
|
|
} else {
|
|
explicit_align = Some(layout.align);
|
|
if !ctx.options().rust_features.repr_align {
|
|
let ty = helpers::blob(
|
|
ctx,
|
|
Layout::new(0, layout.align),
|
|
);
|
|
fields.push(quote! {
|
|
pub __bindgen_align: #ty ,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if is_union && !forward_decl {
|
|
// TODO(emilio): It'd be nice to unify this with the struct path
|
|
// above somehow.
|
|
let layout = layout.expect("Unable to get layout information?");
|
|
if struct_layout.requires_explicit_align(layout) {
|
|
explicit_align = Some(layout.align);
|
|
}
|
|
|
|
if !struct_layout.is_rust_union() {
|
|
let ty = helpers::blob(ctx, layout);
|
|
fields.push(quote! {
|
|
pub bindgen_union_field: #ty ,
|
|
})
|
|
}
|
|
}
|
|
|
|
if forward_decl {
|
|
fields.push(quote! {
|
|
_unused: [u8; 0],
|
|
});
|
|
}
|
|
|
|
let mut generic_param_names = vec![];
|
|
|
|
for (idx, ty) in item.used_template_params(ctx).iter().enumerate() {
|
|
let param = ctx.resolve_type(*ty);
|
|
let name = param.name().unwrap();
|
|
let ident = ctx.rust_ident(name);
|
|
generic_param_names.push(ident.clone());
|
|
|
|
let prefix = ctx.trait_prefix();
|
|
let field_name = ctx.rust_ident(format!("_phantom_{}", idx));
|
|
fields.push(quote! {
|
|
pub #field_name : ::#prefix::marker::PhantomData<
|
|
::#prefix::cell::UnsafeCell<#ident>
|
|
> ,
|
|
});
|
|
}
|
|
|
|
let generics = if !generic_param_names.is_empty() {
|
|
let generic_param_names = generic_param_names.clone();
|
|
quote! {
|
|
< #( #generic_param_names ),* >
|
|
}
|
|
} else {
|
|
quote! {}
|
|
};
|
|
|
|
let mut attributes = vec![];
|
|
let mut needs_clone_impl = false;
|
|
let mut needs_default_impl = false;
|
|
let mut needs_debug_impl = false;
|
|
let mut needs_partialeq_impl = false;
|
|
if let Some(comment) = item.comment(ctx) {
|
|
attributes.push(attributes::doc(comment));
|
|
}
|
|
|
|
// if a type has both a "packed" attribute and an "align(N)" attribute, then check if the
|
|
// "packed" attr is redundant, and do not include it if so.
|
|
if packed &&
|
|
!is_opaque &&
|
|
!(explicit_align.is_some() &&
|
|
self.already_packed(ctx).unwrap_or(false))
|
|
{
|
|
let n = layout.map_or(1, |l| l.align);
|
|
assert!(ctx.options().rust_features().repr_packed_n || n == 1);
|
|
let packed_repr = if n == 1 {
|
|
"packed".to_string()
|
|
} else {
|
|
format!("packed({})", n)
|
|
};
|
|
attributes.push(attributes::repr_list(&["C", &packed_repr]));
|
|
} else {
|
|
attributes.push(attributes::repr("C"));
|
|
}
|
|
|
|
if ctx.options().rust_features().repr_align {
|
|
if let Some(explicit) = explicit_align {
|
|
// Ensure that the struct has the correct alignment even in
|
|
// presence of alignas.
|
|
let explicit = helpers::ast_ty::int_expr(explicit as i64);
|
|
attributes.push(quote! {
|
|
#[repr(align(#explicit))]
|
|
});
|
|
}
|
|
}
|
|
|
|
let derivable_traits = derives_of_item(item, ctx, packed);
|
|
if !derivable_traits.contains(DerivableTraits::DEBUG) {
|
|
needs_debug_impl = ctx.options().derive_debug &&
|
|
ctx.options().impl_debug &&
|
|
!ctx.no_debug_by_name(item) &&
|
|
!item.annotations().disallow_debug();
|
|
}
|
|
|
|
if !derivable_traits.contains(DerivableTraits::DEFAULT) {
|
|
needs_default_impl = ctx.options().derive_default &&
|
|
!self.is_forward_declaration() &&
|
|
!ctx.no_default_by_name(item) &&
|
|
!item.annotations().disallow_default();
|
|
}
|
|
|
|
let all_template_params = item.all_template_params(ctx);
|
|
|
|
if derivable_traits.contains(DerivableTraits::COPY) &&
|
|
!derivable_traits.contains(DerivableTraits::CLONE)
|
|
{
|
|
needs_clone_impl = true;
|
|
}
|
|
|
|
if !derivable_traits.contains(DerivableTraits::PARTIAL_EQ) {
|
|
needs_partialeq_impl = ctx.options().derive_partialeq &&
|
|
ctx.options().impl_partialeq &&
|
|
ctx.lookup_can_derive_partialeq_or_partialord(item.id()) ==
|
|
CanDerive::Manually;
|
|
}
|
|
|
|
let mut derives: Vec<_> = derivable_traits.into();
|
|
derives.extend(item.annotations().derives().iter().map(String::as_str));
|
|
|
|
let is_rust_union = is_union && struct_layout.is_rust_union();
|
|
|
|
// The custom derives callback may return a list of derive attributes;
|
|
// add them to the end of the list.
|
|
let custom_derives = ctx.options().all_callbacks(|cb| {
|
|
cb.add_derives(&DeriveInfo {
|
|
name: &canonical_name,
|
|
kind: if is_rust_union {
|
|
DeriveTypeKind::Union
|
|
} else {
|
|
DeriveTypeKind::Struct
|
|
},
|
|
})
|
|
});
|
|
// In most cases this will be a no-op, since custom_derives will be empty.
|
|
derives.extend(custom_derives.iter().map(|s| s.as_str()));
|
|
|
|
if !derives.is_empty() {
|
|
attributes.push(attributes::derives(&derives))
|
|
}
|
|
|
|
if item.must_use(ctx) {
|
|
attributes.push(attributes::must_use());
|
|
}
|
|
|
|
let mut tokens = if is_rust_union {
|
|
quote! {
|
|
#( #attributes )*
|
|
pub union #canonical_ident
|
|
}
|
|
} else {
|
|
quote! {
|
|
#( #attributes )*
|
|
pub struct #canonical_ident
|
|
}
|
|
};
|
|
|
|
tokens.append_all(quote! {
|
|
#generics {
|
|
#( #fields )*
|
|
}
|
|
});
|
|
result.push(tokens);
|
|
|
|
// Generate the inner types and all that stuff.
|
|
//
|
|
// TODO: In the future we might want to be smart, and use nested
|
|
// modules, and whatnot.
|
|
for ty in self.inner_types() {
|
|
let child_item = ctx.resolve_item(*ty);
|
|
// assert_eq!(child_item.parent_id(), item.id());
|
|
child_item.codegen(ctx, result, &());
|
|
}
|
|
|
|
// NOTE: Some unexposed attributes (like alignment attributes) may
|
|
// affect layout, so we're bad and pray to the gods for avoid sending
|
|
// all the tests to shit when parsing things like max_align_t.
|
|
if self.found_unknown_attr() {
|
|
warn!(
|
|
"Type {} has an unknown attribute that may affect layout",
|
|
canonical_ident
|
|
);
|
|
}
|
|
|
|
if all_template_params.is_empty() {
|
|
if !is_opaque {
|
|
for var in self.inner_vars() {
|
|
ctx.resolve_item(*var).codegen(ctx, result, &());
|
|
}
|
|
}
|
|
|
|
if ctx.options().layout_tests && !self.is_forward_declaration() {
|
|
if let Some(layout) = layout {
|
|
let fn_name =
|
|
format!("bindgen_test_layout_{}", canonical_ident);
|
|
let fn_name = ctx.rust_ident_raw(fn_name);
|
|
let prefix = ctx.trait_prefix();
|
|
let size_of_expr = quote! {
|
|
::#prefix::mem::size_of::<#canonical_ident>()
|
|
};
|
|
let align_of_expr = quote! {
|
|
::#prefix::mem::align_of::<#canonical_ident>()
|
|
};
|
|
let size = layout.size;
|
|
let align = layout.align;
|
|
|
|
let check_struct_align = if align >
|
|
ctx.target_pointer_size() &&
|
|
!ctx.options().rust_features().repr_align
|
|
{
|
|
None
|
|
} else {
|
|
Some(quote! {
|
|
assert_eq!(#align_of_expr,
|
|
#align,
|
|
concat!("Alignment of ", stringify!(#canonical_ident)));
|
|
|
|
})
|
|
};
|
|
|
|
let should_skip_field_offset_checks = is_opaque;
|
|
|
|
let check_field_offset = if should_skip_field_offset_checks
|
|
{
|
|
vec![]
|
|
} else {
|
|
self.fields()
|
|
.iter()
|
|
.filter_map(|field| match *field {
|
|
Field::DataMember(ref f) if f.name().is_some() => Some(f),
|
|
_ => None,
|
|
})
|
|
.flat_map(|field| {
|
|
let name = field.name().unwrap();
|
|
field.offset().map(|offset| {
|
|
let field_offset = offset / 8;
|
|
let field_name = ctx.rust_ident(name);
|
|
quote! {
|
|
assert_eq!(
|
|
unsafe {
|
|
::#prefix::ptr::addr_of!((*ptr).#field_name) as usize - ptr as usize
|
|
},
|
|
#field_offset,
|
|
concat!("Offset of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name))
|
|
);
|
|
}
|
|
})
|
|
})
|
|
.collect()
|
|
};
|
|
|
|
let uninit_decl = if !check_field_offset.is_empty() {
|
|
// FIXME: When MSRV >= 1.59.0, we can use
|
|
// > const PTR: *const #canonical_ident = ::#prefix::mem::MaybeUninit::uninit().as_ptr();
|
|
Some(quote! {
|
|
// Use a shared MaybeUninit so that rustc with
|
|
// opt-level=0 doesn't take too much stack space,
|
|
// see #2218.
|
|
const UNINIT: ::#prefix::mem::MaybeUninit<#canonical_ident> = ::#prefix::mem::MaybeUninit::uninit();
|
|
let ptr = UNINIT.as_ptr();
|
|
})
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let item = quote! {
|
|
#[test]
|
|
fn #fn_name() {
|
|
#uninit_decl
|
|
assert_eq!(#size_of_expr,
|
|
#size,
|
|
concat!("Size of: ", stringify!(#canonical_ident)));
|
|
#check_struct_align
|
|
#( #check_field_offset )*
|
|
}
|
|
};
|
|
result.push(item);
|
|
}
|
|
}
|
|
|
|
let mut method_names = Default::default();
|
|
if ctx.options().codegen_config.methods() {
|
|
for method in self.methods() {
|
|
assert!(method.kind() != MethodKind::Constructor);
|
|
method.codegen_method(
|
|
ctx,
|
|
&mut methods,
|
|
&mut method_names,
|
|
result,
|
|
self,
|
|
);
|
|
}
|
|
}
|
|
|
|
if ctx.options().codegen_config.constructors() {
|
|
for sig in self.constructors() {
|
|
Method::new(
|
|
MethodKind::Constructor,
|
|
*sig,
|
|
/* const */
|
|
false,
|
|
)
|
|
.codegen_method(
|
|
ctx,
|
|
&mut methods,
|
|
&mut method_names,
|
|
result,
|
|
self,
|
|
);
|
|
}
|
|
}
|
|
|
|
if ctx.options().codegen_config.destructors() {
|
|
if let Some((kind, destructor)) = self.destructor() {
|
|
debug_assert!(kind.is_destructor());
|
|
Method::new(kind, destructor, false).codegen_method(
|
|
ctx,
|
|
&mut methods,
|
|
&mut method_names,
|
|
result,
|
|
self,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// NB: We can't use to_rust_ty here since for opaque types this tries to
|
|
// use the specialization knowledge to generate a blob field.
|
|
let ty_for_impl = quote! {
|
|
#canonical_ident #generics
|
|
};
|
|
|
|
if needs_clone_impl {
|
|
result.push(quote! {
|
|
impl #generics Clone for #ty_for_impl {
|
|
fn clone(&self) -> Self { *self }
|
|
}
|
|
});
|
|
}
|
|
|
|
if needs_default_impl {
|
|
let prefix = ctx.trait_prefix();
|
|
let body = if ctx.options().rust_features().maybe_uninit {
|
|
quote! {
|
|
let mut s = ::#prefix::mem::MaybeUninit::<Self>::uninit();
|
|
unsafe {
|
|
::#prefix::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
|
s.assume_init()
|
|
}
|
|
}
|
|
} else {
|
|
quote! {
|
|
unsafe {
|
|
let mut s: Self = ::#prefix::mem::uninitialized();
|
|
::#prefix::ptr::write_bytes(&mut s, 0, 1);
|
|
s
|
|
}
|
|
}
|
|
};
|
|
// Note we use `ptr::write_bytes()` instead of `mem::zeroed()` because the latter does
|
|
// not necessarily ensure padding bytes are zeroed. Some C libraries are sensitive to
|
|
// non-zero padding bytes, especially when forwards/backwards compatability is
|
|
// involved.
|
|
result.push(quote! {
|
|
impl #generics Default for #ty_for_impl {
|
|
fn default() -> Self {
|
|
#body
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if needs_debug_impl {
|
|
let impl_ = impl_debug::gen_debug_impl(
|
|
ctx,
|
|
self.fields(),
|
|
item,
|
|
self.kind(),
|
|
);
|
|
|
|
let prefix = ctx.trait_prefix();
|
|
|
|
result.push(quote! {
|
|
impl #generics ::#prefix::fmt::Debug for #ty_for_impl {
|
|
#impl_
|
|
}
|
|
});
|
|
}
|
|
|
|
if needs_partialeq_impl {
|
|
if let Some(impl_) = impl_partialeq::gen_partialeq_impl(
|
|
ctx,
|
|
self,
|
|
item,
|
|
&ty_for_impl,
|
|
) {
|
|
let partialeq_bounds = if !generic_param_names.is_empty() {
|
|
let bounds = generic_param_names.iter().map(|t| {
|
|
quote! { #t: PartialEq }
|
|
});
|
|
quote! { where #( #bounds ),* }
|
|
} else {
|
|
quote! {}
|
|
};
|
|
|
|
let prefix = ctx.trait_prefix();
|
|
result.push(quote! {
|
|
impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds {
|
|
#impl_
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if !methods.is_empty() {
|
|
result.push(quote! {
|
|
impl #generics #ty_for_impl {
|
|
#( #methods )*
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Method {
|
|
fn codegen_method(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
methods: &mut Vec<proc_macro2::TokenStream>,
|
|
method_names: &mut HashSet<String>,
|
|
result: &mut CodegenResult<'_>,
|
|
_parent: &CompInfo,
|
|
) {
|
|
assert!({
|
|
let cc = &ctx.options().codegen_config;
|
|
match self.kind() {
|
|
MethodKind::Constructor => cc.constructors(),
|
|
MethodKind::Destructor => cc.destructors(),
|
|
MethodKind::VirtualDestructor { .. } => cc.destructors(),
|
|
MethodKind::Static |
|
|
MethodKind::Normal |
|
|
MethodKind::Virtual { .. } => cc.methods(),
|
|
}
|
|
});
|
|
|
|
// TODO(emilio): We could generate final stuff at least.
|
|
if self.is_virtual() {
|
|
return; // FIXME
|
|
}
|
|
|
|
// First of all, output the actual function.
|
|
let function_item = ctx.resolve_item(self.signature());
|
|
if !function_item.process_before_codegen(ctx, result) {
|
|
return;
|
|
}
|
|
let function = function_item.expect_function();
|
|
let times_seen = function.codegen(ctx, result, function_item);
|
|
let times_seen = match times_seen {
|
|
Some(seen) => seen,
|
|
None => return,
|
|
};
|
|
let signature_item = ctx.resolve_item(function.signature());
|
|
let mut name = match self.kind() {
|
|
MethodKind::Constructor => "new".into(),
|
|
MethodKind::Destructor => "destruct".into(),
|
|
_ => function.name().to_owned(),
|
|
};
|
|
|
|
let signature = match *signature_item.expect_type().kind() {
|
|
TypeKind::Function(ref sig) => sig,
|
|
_ => panic!("How in the world?"),
|
|
};
|
|
|
|
let supported_abi = signature.abi(ctx, Some(&*name)).is_ok();
|
|
if !supported_abi {
|
|
return;
|
|
}
|
|
|
|
// Do not generate variadic methods, since rust does not allow
|
|
// implementing them, and we don't do a good job at it anyway.
|
|
if signature.is_variadic() {
|
|
return;
|
|
}
|
|
|
|
if method_names.contains(&name) {
|
|
let mut count = 1;
|
|
let mut new_name;
|
|
|
|
while {
|
|
new_name = format!("{}{}", name, count);
|
|
method_names.contains(&new_name)
|
|
} {
|
|
count += 1;
|
|
}
|
|
|
|
name = new_name;
|
|
}
|
|
|
|
method_names.insert(name.clone());
|
|
|
|
let mut function_name = function_item.canonical_name(ctx);
|
|
if times_seen > 0 {
|
|
write!(&mut function_name, "{}", times_seen).unwrap();
|
|
}
|
|
let function_name = ctx.rust_ident(function_name);
|
|
let mut args = utils::fnsig_arguments(ctx, signature);
|
|
let mut ret = utils::fnsig_return_ty(ctx, signature);
|
|
|
|
if !self.is_static() && !self.is_constructor() {
|
|
args[0] = if self.is_const() {
|
|
quote! { &self }
|
|
} else {
|
|
quote! { &mut self }
|
|
};
|
|
}
|
|
|
|
// If it's a constructor, we always return `Self`, and we inject the
|
|
// "this" parameter, so there's no need to ask the user for it.
|
|
//
|
|
// Note that constructors in Clang are represented as functions with
|
|
// return-type = void.
|
|
if self.is_constructor() {
|
|
args.remove(0);
|
|
ret = quote! { -> Self };
|
|
}
|
|
|
|
let mut exprs =
|
|
helpers::ast_ty::arguments_from_signature(signature, ctx);
|
|
|
|
let mut stmts = vec![];
|
|
|
|
// If it's a constructor, we need to insert an extra parameter with a
|
|
// variable called `__bindgen_tmp` we're going to create.
|
|
if self.is_constructor() {
|
|
let prefix = ctx.trait_prefix();
|
|
let tmp_variable_decl = if ctx
|
|
.options()
|
|
.rust_features()
|
|
.maybe_uninit
|
|
{
|
|
exprs[0] = quote! {
|
|
__bindgen_tmp.as_mut_ptr()
|
|
};
|
|
quote! {
|
|
let mut __bindgen_tmp = ::#prefix::mem::MaybeUninit::uninit()
|
|
}
|
|
} else {
|
|
exprs[0] = quote! {
|
|
&mut __bindgen_tmp
|
|
};
|
|
quote! {
|
|
let mut __bindgen_tmp = ::#prefix::mem::uninitialized()
|
|
}
|
|
};
|
|
stmts.push(tmp_variable_decl);
|
|
} else if !self.is_static() {
|
|
assert!(!exprs.is_empty());
|
|
exprs[0] = quote! {
|
|
self
|
|
};
|
|
};
|
|
|
|
let call = quote! {
|
|
#function_name (#( #exprs ),* )
|
|
};
|
|
|
|
stmts.push(call);
|
|
|
|
if self.is_constructor() {
|
|
stmts.push(if ctx.options().rust_features().maybe_uninit {
|
|
quote! {
|
|
__bindgen_tmp.assume_init()
|
|
}
|
|
} else {
|
|
quote! {
|
|
__bindgen_tmp
|
|
}
|
|
})
|
|
}
|
|
|
|
let block = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*));
|
|
|
|
let mut attrs = vec![attributes::inline()];
|
|
|
|
if signature.must_use() &&
|
|
ctx.options().rust_features().must_use_function
|
|
{
|
|
attrs.push(attributes::must_use());
|
|
}
|
|
|
|
let name = ctx.rust_ident(&name);
|
|
methods.push(quote! {
|
|
#(#attrs)*
|
|
pub unsafe fn #name ( #( #args ),* ) #ret {
|
|
#block
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/// A helper type that represents different enum variations.
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
pub enum EnumVariation {
|
|
/// The code for this enum will use a Rust enum. Note that creating this in unsafe code
|
|
/// (including FFI) with an invalid value will invoke undefined behaviour, whether or not
|
|
/// its marked as non_exhaustive.
|
|
Rust {
|
|
/// Indicates whether the generated struct should be `#[non_exhaustive]`
|
|
non_exhaustive: bool,
|
|
},
|
|
/// The code for this enum will use a newtype
|
|
NewType {
|
|
/// Indicates whether the newtype will have bitwise operators
|
|
is_bitfield: bool,
|
|
/// Indicates whether the variants will be represented as global constants
|
|
is_global: bool,
|
|
},
|
|
/// The code for this enum will use consts
|
|
Consts,
|
|
/// The code for this enum will use a module containing consts
|
|
ModuleConsts,
|
|
}
|
|
|
|
impl EnumVariation {
|
|
fn is_rust(&self) -> bool {
|
|
matches!(*self, EnumVariation::Rust { .. })
|
|
}
|
|
|
|
/// Both the `Const` and `ModuleConsts` variants will cause this to return
|
|
/// true.
|
|
fn is_const(&self) -> bool {
|
|
matches!(*self, EnumVariation::Consts | EnumVariation::ModuleConsts)
|
|
}
|
|
}
|
|
|
|
impl Default for EnumVariation {
|
|
fn default() -> EnumVariation {
|
|
EnumVariation::Consts
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for EnumVariation {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let s = match self {
|
|
Self::Rust {
|
|
non_exhaustive: false,
|
|
} => "rust",
|
|
Self::Rust {
|
|
non_exhaustive: true,
|
|
} => "rust_non_exhaustive",
|
|
Self::NewType {
|
|
is_bitfield: true, ..
|
|
} => "bitfield",
|
|
Self::NewType {
|
|
is_bitfield: false,
|
|
is_global,
|
|
} => {
|
|
if *is_global {
|
|
"newtype_global"
|
|
} else {
|
|
"newtype"
|
|
}
|
|
}
|
|
Self::Consts => "consts",
|
|
Self::ModuleConsts => "moduleconsts",
|
|
};
|
|
s.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl std::str::FromStr for EnumVariation {
|
|
type Err = std::io::Error;
|
|
|
|
/// Create a `EnumVariation` from a string.
|
|
fn from_str(s: &str) -> Result<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'."
|
|
),
|
|
)),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A helper type to construct different enum variations.
|
|
enum EnumBuilder<'a> {
|
|
Rust {
|
|
attrs: Vec<proc_macro2::TokenStream>,
|
|
ident: Ident,
|
|
tokens: proc_macro2::TokenStream,
|
|
emitted_any_variants: bool,
|
|
},
|
|
NewType {
|
|
canonical_name: &'a str,
|
|
tokens: proc_macro2::TokenStream,
|
|
is_bitfield: bool,
|
|
is_global: bool,
|
|
},
|
|
Consts {
|
|
variants: Vec<proc_macro2::TokenStream>,
|
|
},
|
|
ModuleConsts {
|
|
module_name: &'a str,
|
|
module_items: Vec<proc_macro2::TokenStream>,
|
|
},
|
|
}
|
|
|
|
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());
|
|
|
|
match enum_variation {
|
|
EnumVariation::NewType {
|
|
is_bitfield,
|
|
is_global,
|
|
} => EnumBuilder::NewType {
|
|
canonical_name: name,
|
|
tokens: quote! {
|
|
#( #attrs )*
|
|
pub struct #ident (pub #repr);
|
|
},
|
|
is_bitfield,
|
|
is_global,
|
|
},
|
|
|
|
EnumVariation::Rust { .. } => {
|
|
// `repr` is guaranteed to be Rustified in Enum::codegen
|
|
attrs.insert(0, quote! { #[repr( #repr )] });
|
|
let tokens = quote!();
|
|
EnumBuilder::Rust {
|
|
attrs,
|
|
ident,
|
|
tokens,
|
|
emitted_any_variants: false,
|
|
}
|
|
}
|
|
|
|
EnumVariation::Consts => {
|
|
let mut variants = Vec::new();
|
|
|
|
if !has_typedef {
|
|
variants.push(quote! {
|
|
#( #attrs )*
|
|
pub type #ident = #repr;
|
|
});
|
|
}
|
|
|
|
EnumBuilder::Consts { variants }
|
|
}
|
|
|
|
EnumVariation::ModuleConsts => {
|
|
let ident = Ident::new(
|
|
CONSTIFIED_ENUM_MODULE_REPR_NAME,
|
|
Span::call_site(),
|
|
);
|
|
let type_definition = quote! {
|
|
#( #attrs )*
|
|
pub type #ident = #repr;
|
|
};
|
|
|
|
EnumBuilder::ModuleConsts {
|
|
module_name: name,
|
|
module_items: vec![type_definition],
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Add a variant to this enum.
|
|
fn with_variant(
|
|
self,
|
|
ctx: &BindgenContext,
|
|
variant: &EnumVariant,
|
|
mangling_prefix: Option<&str>,
|
|
rust_ty: syn::Type,
|
|
result: &mut CodegenResult<'_>,
|
|
is_ty_named: bool,
|
|
) -> Self {
|
|
let variant_name = ctx.rust_mangle(variant.name());
|
|
let is_rust_enum = self.is_rust_enum();
|
|
let expr = match variant.val() {
|
|
EnumVariantValue::Boolean(v) if is_rust_enum => {
|
|
helpers::ast_ty::uint_expr(v as u64)
|
|
}
|
|
EnumVariantValue::Boolean(v) => quote!(#v),
|
|
EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v),
|
|
EnumVariantValue::Unsigned(v) => helpers::ast_ty::uint_expr(v),
|
|
};
|
|
|
|
let mut doc = quote! {};
|
|
if ctx.options().generate_comments {
|
|
if let Some(raw_comment) = variant.comment() {
|
|
let comment = ctx.options().process_comment(raw_comment);
|
|
doc = attributes::doc(comment);
|
|
}
|
|
}
|
|
|
|
match self {
|
|
EnumBuilder::Rust {
|
|
attrs,
|
|
ident,
|
|
tokens,
|
|
emitted_any_variants: _,
|
|
} => {
|
|
let name = ctx.rust_ident(variant_name);
|
|
EnumBuilder::Rust {
|
|
attrs,
|
|
ident,
|
|
tokens: quote! {
|
|
#tokens
|
|
#doc
|
|
#name = #expr,
|
|
},
|
|
emitted_any_variants: true,
|
|
}
|
|
}
|
|
|
|
EnumBuilder::NewType {
|
|
canonical_name,
|
|
is_global,
|
|
..
|
|
} => {
|
|
if ctx.options().rust_features().associated_const &&
|
|
is_ty_named &&
|
|
!is_global
|
|
{
|
|
let enum_ident = ctx.rust_ident(canonical_name);
|
|
let variant_ident = ctx.rust_ident(variant_name);
|
|
|
|
result.push(quote! {
|
|
impl #enum_ident {
|
|
#doc
|
|
pub const #variant_ident : #rust_ty = #rust_ty ( #expr );
|
|
}
|
|
});
|
|
} else {
|
|
let ident = ctx.rust_ident(match mangling_prefix {
|
|
Some(prefix) => {
|
|
Cow::Owned(format!("{}_{}", prefix, variant_name))
|
|
}
|
|
None => variant_name,
|
|
});
|
|
result.push(quote! {
|
|
#doc
|
|
pub const #ident : #rust_ty = #rust_ty ( #expr );
|
|
});
|
|
}
|
|
|
|
self
|
|
}
|
|
|
|
EnumBuilder::Consts { .. } => {
|
|
let constant_name = match mangling_prefix {
|
|
Some(prefix) => {
|
|
Cow::Owned(format!("{}_{}", prefix, variant_name))
|
|
}
|
|
None => variant_name,
|
|
};
|
|
|
|
let ident = ctx.rust_ident(constant_name);
|
|
result.push(quote! {
|
|
#doc
|
|
pub const #ident : #rust_ty = #expr ;
|
|
});
|
|
|
|
self
|
|
}
|
|
EnumBuilder::ModuleConsts {
|
|
module_name,
|
|
mut module_items,
|
|
} => {
|
|
let name = ctx.rust_ident(variant_name);
|
|
let ty = ctx.rust_ident(CONSTIFIED_ENUM_MODULE_REPR_NAME);
|
|
module_items.push(quote! {
|
|
#doc
|
|
pub const #name : #ty = #expr ;
|
|
});
|
|
|
|
EnumBuilder::ModuleConsts {
|
|
module_name,
|
|
module_items,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn build(
|
|
self,
|
|
ctx: &BindgenContext,
|
|
rust_ty: syn::Type,
|
|
result: &mut CodegenResult<'_>,
|
|
) -> proc_macro2::TokenStream {
|
|
match self {
|
|
EnumBuilder::Rust {
|
|
attrs,
|
|
ident,
|
|
tokens,
|
|
emitted_any_variants,
|
|
..
|
|
} => {
|
|
let variants = if !emitted_any_variants {
|
|
quote!(__bindgen_cannot_repr_c_on_empty_enum = 0)
|
|
} else {
|
|
tokens
|
|
};
|
|
|
|
quote! {
|
|
#( #attrs )*
|
|
pub enum #ident {
|
|
#variants
|
|
}
|
|
}
|
|
}
|
|
EnumBuilder::NewType {
|
|
canonical_name,
|
|
tokens,
|
|
is_bitfield,
|
|
..
|
|
} => {
|
|
if !is_bitfield {
|
|
return tokens;
|
|
}
|
|
|
|
let rust_ty_name = ctx.rust_ident_raw(canonical_name);
|
|
let prefix = ctx.trait_prefix();
|
|
|
|
result.push(quote! {
|
|
impl ::#prefix::ops::BitOr<#rust_ty> for #rust_ty {
|
|
type Output = Self;
|
|
|
|
#[inline]
|
|
fn bitor(self, other: Self) -> Self {
|
|
#rust_ty_name(self.0 | other.0)
|
|
}
|
|
}
|
|
});
|
|
|
|
result.push(quote! {
|
|
impl ::#prefix::ops::BitOrAssign for #rust_ty {
|
|
#[inline]
|
|
fn bitor_assign(&mut self, rhs: #rust_ty) {
|
|
self.0 |= rhs.0;
|
|
}
|
|
}
|
|
});
|
|
|
|
result.push(quote! {
|
|
impl ::#prefix::ops::BitAnd<#rust_ty> for #rust_ty {
|
|
type Output = Self;
|
|
|
|
#[inline]
|
|
fn bitand(self, other: Self) -> Self {
|
|
#rust_ty_name(self.0 & other.0)
|
|
}
|
|
}
|
|
});
|
|
|
|
result.push(quote! {
|
|
impl ::#prefix::ops::BitAndAssign for #rust_ty {
|
|
#[inline]
|
|
fn bitand_assign(&mut self, rhs: #rust_ty) {
|
|
self.0 &= rhs.0;
|
|
}
|
|
}
|
|
});
|
|
|
|
tokens
|
|
}
|
|
EnumBuilder::Consts { variants, .. } => quote! { #( #variants )* },
|
|
EnumBuilder::ModuleConsts {
|
|
module_items,
|
|
module_name,
|
|
..
|
|
} => {
|
|
let ident = ctx.rust_ident(module_name);
|
|
quote! {
|
|
pub mod #ident {
|
|
#( #module_items )*
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CodeGenerator for Enum {
|
|
type Extra = Item;
|
|
type Return = ();
|
|
|
|
fn codegen(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
result: &mut CodegenResult<'_>,
|
|
item: &Item,
|
|
) {
|
|
debug!("<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 = match repr {
|
|
Some(repr) => match *repr.canonical_type(ctx).kind() {
|
|
TypeKind::Int(int_kind) => int_kind,
|
|
_ => panic!("Unexpected type as enum repr"),
|
|
},
|
|
None => {
|
|
warn!(
|
|
"Guessing type of enum! Forward declarations of enums \
|
|
shouldn't be legal!"
|
|
);
|
|
IntKind::Int
|
|
}
|
|
};
|
|
|
|
let signed = kind.is_signed();
|
|
let size = layout
|
|
.map(|l| l.size)
|
|
.or_else(|| kind.known_size())
|
|
.unwrap_or(0);
|
|
|
|
let translated = match (signed, size) {
|
|
(true, 1) => IntKind::I8,
|
|
(false, 1) => IntKind::U8,
|
|
(true, 2) => IntKind::I16,
|
|
(false, 2) => IntKind::U16,
|
|
(true, 4) => IntKind::I32,
|
|
(false, 4) => IntKind::U32,
|
|
(true, 8) => IntKind::I64,
|
|
(false, 8) => IntKind::U64,
|
|
_ => {
|
|
warn!(
|
|
"invalid enum decl: signed: {}, size: {}",
|
|
signed, size
|
|
);
|
|
IntKind::I32
|
|
}
|
|
};
|
|
|
|
repr_translated =
|
|
Type::new(None, None, TypeKind::Int(translated), false);
|
|
&repr_translated
|
|
}
|
|
};
|
|
|
|
let mut attrs = vec![];
|
|
|
|
// TODO(emilio): Delegate this to the builders?
|
|
match variation {
|
|
EnumVariation::Rust { non_exhaustive } => {
|
|
if non_exhaustive &&
|
|
ctx.options().rust_features().non_exhaustive
|
|
{
|
|
attrs.push(attributes::non_exhaustive());
|
|
} else if non_exhaustive &&
|
|
!ctx.options().rust_features().non_exhaustive
|
|
{
|
|
panic!("The rust target you're using doesn't seem to support non_exhaustive enums");
|
|
}
|
|
}
|
|
EnumVariation::NewType { .. } => {
|
|
if ctx.options().rust_features.repr_transparent {
|
|
attrs.push(attributes::repr("transparent"));
|
|
} else {
|
|
attrs.push(attributes::repr("C"));
|
|
}
|
|
}
|
|
_ => {}
|
|
};
|
|
|
|
if let Some(comment) = item.comment(ctx) {
|
|
attrs.push(attributes::doc(comment));
|
|
}
|
|
|
|
if item.must_use(ctx) {
|
|
attrs.push(attributes::must_use());
|
|
}
|
|
|
|
if !variation.is_const() {
|
|
let packed = false; // Enums can't be packed in Rust.
|
|
let mut derives = derives_of_item(item, ctx, packed);
|
|
// For backwards compat, enums always derive
|
|
// Clone/Eq/PartialEq/Hash, even if we don't generate those by
|
|
// default.
|
|
derives.insert(
|
|
DerivableTraits::CLONE |
|
|
DerivableTraits::HASH |
|
|
DerivableTraits::PARTIAL_EQ |
|
|
DerivableTraits::EQ,
|
|
);
|
|
let mut derives: Vec<_> = derives.into();
|
|
for derive in item.annotations().derives().iter() {
|
|
if !derives.contains(&derive.as_str()) {
|
|
derives.push(derive);
|
|
}
|
|
}
|
|
|
|
// The custom derives callback may return a list of derive attributes;
|
|
// add them to the end of the list.
|
|
let custom_derives = ctx.options().all_callbacks(|cb| {
|
|
cb.add_derives(&DeriveInfo {
|
|
name: &name,
|
|
kind: DeriveTypeKind::Enum,
|
|
})
|
|
});
|
|
// In most cases this will be a no-op, since custom_derives will be empty.
|
|
derives.extend(custom_derives.iter().map(|s| s.as_str()));
|
|
|
|
attrs.push(attributes::derives(&derives));
|
|
}
|
|
|
|
fn add_constant(
|
|
ctx: &BindgenContext,
|
|
enum_: &Type,
|
|
// Only to avoid recomputing every time.
|
|
enum_canonical_name: &Ident,
|
|
// May be the same as "variant" if it's because the
|
|
// enum is unnamed and we still haven't seen the
|
|
// value.
|
|
variant_name: &Ident,
|
|
referenced_name: &Ident,
|
|
enum_rust_ty: syn::Type,
|
|
result: &mut CodegenResult<'_>,
|
|
) {
|
|
let constant_name = if enum_.name().is_some() {
|
|
if ctx.options().prepend_enum_name {
|
|
format!("{}_{}", enum_canonical_name, variant_name)
|
|
} else {
|
|
format!("{}", variant_name)
|
|
}
|
|
} else {
|
|
format!("{}", variant_name)
|
|
};
|
|
let constant_name = ctx.rust_ident(constant_name);
|
|
|
|
result.push(quote! {
|
|
pub const #constant_name : #enum_rust_ty =
|
|
#enum_canonical_name :: #referenced_name ;
|
|
});
|
|
}
|
|
|
|
let repr = repr.to_rust_ty_or_opaque(ctx, item);
|
|
let has_typedef = ctx.is_enum_typedef_combo(item.id());
|
|
|
|
let mut builder =
|
|
EnumBuilder::new(&name, attrs, repr, variation, has_typedef);
|
|
|
|
// A map where we keep a value -> variant relation.
|
|
let mut seen_values = HashMap::<_, Ident>::default();
|
|
let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &());
|
|
let is_toplevel = item.is_toplevel(ctx);
|
|
|
|
// Used to mangle the constants we generate in the unnamed-enum case.
|
|
let parent_canonical_name = if is_toplevel {
|
|
None
|
|
} else {
|
|
Some(item.parent_id().canonical_name(ctx))
|
|
};
|
|
|
|
let constant_mangling_prefix = if ctx.options().prepend_enum_name {
|
|
if enum_ty.name().is_none() {
|
|
parent_canonical_name.as_deref()
|
|
} else {
|
|
Some(&*name)
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
|
|
// NB: We defer the creation of constified variants, in case we find
|
|
// another variant with the same value (which is the common thing to
|
|
// do).
|
|
let mut constified_variants = VecDeque::new();
|
|
|
|
let mut iter = self.variants().iter().peekable();
|
|
while let Some(variant) =
|
|
iter.next().or_else(|| constified_variants.pop_front())
|
|
{
|
|
if variant.hidden() {
|
|
continue;
|
|
}
|
|
|
|
if variant.force_constification() && iter.peek().is_some() {
|
|
constified_variants.push_back(variant);
|
|
continue;
|
|
}
|
|
|
|
match seen_values.entry(variant.val()) {
|
|
Entry::Occupied(ref entry) => {
|
|
if variation.is_rust() {
|
|
let variant_name = ctx.rust_mangle(variant.name());
|
|
let mangled_name =
|
|
if is_toplevel || enum_ty.name().is_some() {
|
|
variant_name
|
|
} else {
|
|
let parent_name =
|
|
parent_canonical_name.as_ref().unwrap();
|
|
|
|
Cow::Owned(format!(
|
|
"{}_{}",
|
|
parent_name, variant_name
|
|
))
|
|
};
|
|
|
|
let existing_variant_name = entry.get();
|
|
// Use associated constants for named enums.
|
|
if enum_ty.name().is_some() &&
|
|
ctx.options().rust_features().associated_const
|
|
{
|
|
let enum_canonical_name = &ident;
|
|
let variant_name =
|
|
ctx.rust_ident_raw(&*mangled_name);
|
|
result.push(quote! {
|
|
impl #enum_rust_ty {
|
|
pub const #variant_name : #enum_rust_ty =
|
|
#enum_canonical_name :: #existing_variant_name ;
|
|
}
|
|
});
|
|
} else {
|
|
add_constant(
|
|
ctx,
|
|
enum_ty,
|
|
&ident,
|
|
&Ident::new(&mangled_name, Span::call_site()),
|
|
existing_variant_name,
|
|
enum_rust_ty.clone(),
|
|
result,
|
|
);
|
|
}
|
|
} else {
|
|
builder = builder.with_variant(
|
|
ctx,
|
|
variant,
|
|
constant_mangling_prefix,
|
|
enum_rust_ty.clone(),
|
|
result,
|
|
enum_ty.name().is_some(),
|
|
);
|
|
}
|
|
}
|
|
Entry::Vacant(entry) => {
|
|
builder = builder.with_variant(
|
|
ctx,
|
|
variant,
|
|
constant_mangling_prefix,
|
|
enum_rust_ty.clone(),
|
|
result,
|
|
enum_ty.name().is_some(),
|
|
);
|
|
|
|
let variant_name = ctx.rust_ident(variant.name());
|
|
|
|
// If it's an unnamed enum, or constification is enforced,
|
|
// we also generate a constant so it can be properly
|
|
// accessed.
|
|
if (variation.is_rust() && enum_ty.name().is_none()) ||
|
|
variant.force_constification()
|
|
{
|
|
let mangled_name = if is_toplevel {
|
|
variant_name.clone()
|
|
} else {
|
|
let parent_name =
|
|
parent_canonical_name.as_ref().unwrap();
|
|
|
|
Ident::new(
|
|
&format!("{}_{}", parent_name, variant_name),
|
|
Span::call_site(),
|
|
)
|
|
};
|
|
|
|
add_constant(
|
|
ctx,
|
|
enum_ty,
|
|
&ident,
|
|
&mangled_name,
|
|
&variant_name,
|
|
enum_rust_ty.clone(),
|
|
result,
|
|
);
|
|
}
|
|
|
|
entry.insert(variant_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
let item = builder.build(ctx, enum_rust_ty, result);
|
|
result.push(item);
|
|
}
|
|
}
|
|
|
|
/// Enum for the default type of macro constants.
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
pub enum MacroTypeVariation {
|
|
/// Use i32 or i64
|
|
Signed,
|
|
/// Use u32 or u64
|
|
Unsigned,
|
|
}
|
|
|
|
impl fmt::Display for MacroTypeVariation {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let s = match self {
|
|
Self::Signed => "signed",
|
|
Self::Unsigned => "unsigned",
|
|
};
|
|
s.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl Default for MacroTypeVariation {
|
|
fn default() -> MacroTypeVariation {
|
|
MacroTypeVariation::Unsigned
|
|
}
|
|
}
|
|
|
|
impl std::str::FromStr for MacroTypeVariation {
|
|
type Err = std::io::Error;
|
|
|
|
/// Create a `MacroTypeVariation` from a string.
|
|
fn from_str(s: &str) -> Result<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)]
|
|
pub enum AliasVariation {
|
|
/// Convert to regular Rust alias
|
|
TypeAlias,
|
|
/// Create a new type by wrapping the old type in a struct and using #[repr(transparent)]
|
|
NewType,
|
|
/// Same as NewStruct but also impl Deref to be able to use the methods of the wrapped type
|
|
NewTypeDeref,
|
|
}
|
|
|
|
impl fmt::Display for AliasVariation {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let s = match self {
|
|
Self::TypeAlias => "type_alias",
|
|
Self::NewType => "new_type",
|
|
Self::NewTypeDeref => "new_type_deref",
|
|
};
|
|
|
|
s.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl Default for AliasVariation {
|
|
fn default() -> AliasVariation {
|
|
AliasVariation::TypeAlias
|
|
}
|
|
}
|
|
|
|
impl std::str::FromStr for AliasVariation {
|
|
type Err = std::io::Error;
|
|
|
|
/// Create an `AliasVariation` from a string.
|
|
fn from_str(s: &str) -> Result<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)]
|
|
pub enum NonCopyUnionStyle {
|
|
/// Wrap members in a type generated by `bindgen`.
|
|
BindgenWrapper,
|
|
/// Wrap members in [`::core::mem::ManuallyDrop`].
|
|
///
|
|
/// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your
|
|
/// MSRV is lower.
|
|
ManuallyDrop,
|
|
}
|
|
|
|
impl fmt::Display for NonCopyUnionStyle {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let s = match self {
|
|
Self::BindgenWrapper => "bindgen_wrapper",
|
|
Self::ManuallyDrop => "manually_drop",
|
|
};
|
|
|
|
s.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl Default for NonCopyUnionStyle {
|
|
fn default() -> Self {
|
|
Self::BindgenWrapper
|
|
}
|
|
}
|
|
|
|
impl std::str::FromStr for NonCopyUnionStyle {
|
|
type Err = std::io::Error;
|
|
|
|
fn from_str(s: &str) -> Result<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))
|
|
}
|
|
|
|
fn to_opaque(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
extra: &Self::Extra,
|
|
) -> syn::Type {
|
|
let layout = self.get_layout(ctx, extra);
|
|
helpers::blob(ctx, layout)
|
|
}
|
|
}
|
|
|
|
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))
|
|
} else {
|
|
Err(error::Error::NoLayoutForOpaqueBlob)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Infallible conversion to a Rust type, or an opaque blob with a best effort
|
|
/// of correct size and alignment.
|
|
///
|
|
/// Don't implement this directly. Instead implement `TryToRustTy` and
|
|
/// `TryToOpaque`, and then leverage the blanket impl for this trait below.
|
|
///
|
|
/// ### Fallible vs. Infallible Conversions to Rust Types
|
|
///
|
|
/// When should one use this infallible `ToRustTyOrOpaque` trait versus the
|
|
/// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait
|
|
/// implementations that need to convert another thing into a Rust type or
|
|
/// opaque blob in a nested manner should also use fallible trait methods and
|
|
/// propagate failure up the stack. Only infallible functions and methods like
|
|
/// CodeGenerator implementations should use the infallible
|
|
/// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely
|
|
/// we are to get a usable `Layout` even if we can't generate an equivalent Rust
|
|
/// type for a C++ construct.
|
|
pub(crate) trait ToRustTyOrOpaque: TryToRustTy + ToOpaque {
|
|
type Extra;
|
|
|
|
fn to_rust_ty_or_opaque(
|
|
&self,
|
|
ctx: &BindgenContext,
|
|
extra: &<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::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 {
|
|
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::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::Error::InstantiationOfOpaqueType);
|
|
}
|
|
|
|
let def = self
|
|
.template_definition()
|
|
.into_resolver()
|
|
.through_type_refs()
|
|
.resolve(ctx);
|
|
|
|
let mut ty = quote! {};
|
|
let def_path = def.namespace_aware_canonical_path(ctx);
|
|
ty.append_separated(
|
|
def_path.into_iter().map(|p| ctx.rust_ident(p)),
|
|
quote!(::),
|
|
);
|
|
|
|
let def_params = def.self_template_params(ctx);
|
|
if def_params.is_empty() {
|
|
// This can happen if we generated an opaque type for a partial
|
|
// template specialization, and we've hit an instantiation of
|
|
// that partial specialization.
|
|
extra_assert!(def.is_opaque(ctx, &()));
|
|
return Err(error::Error::InstantiationOfOpaqueType);
|
|
}
|
|
|
|
// TODO: If the definition type is a template class/struct
|
|
// definition's member template definition, it could rely on
|
|
// generic template parameters from its outer template
|
|
// class/struct. When we emit bindings for it, it could require
|
|
// *more* type arguments than we have here, and we will need to
|
|
// reconstruct them somehow. We don't have any means of doing
|
|
// that reconstruction at this time.
|
|
|
|
let template_args = self
|
|
.template_arguments()
|
|
.iter()
|
|
.zip(def_params.iter())
|
|
// Only pass type arguments for the type parameters that
|
|
// the def uses.
|
|
.filter(|&(_, param)| ctx.uses_template_parameter(def.id(), *param))
|
|
.map(|(arg, _)| {
|
|
let arg = arg.into_resolver().through_type_refs().resolve(ctx);
|
|
let ty = arg
|
|
.try_to_rust_ty(ctx, &())?
|
|
.with_implicit_template_params(ctx, arg);
|
|
Ok(ty)
|
|
})
|
|
.collect::<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::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 signature = match *signature.kind() {
|
|
TypeKind::Function(ref sig) => sig,
|
|
_ => panic!("Signature kind is not a Function: {:?}", signature),
|
|
};
|
|
|
|
if is_internal {
|
|
if !ctx.options().wrap_static_fns {
|
|
// We cannot do anything with internal functions if we are not wrapping them so
|
|
// just avoid generating anything for them.
|
|
return None;
|
|
}
|
|
|
|
if signature.is_variadic() {
|
|
// We cannot generate wrappers for variadic static functions so we avoid
|
|
// generating any code for them.
|
|
variadic_fn_diagnostic(self.name(), item.location(), ctx);
|
|
return None;
|
|
}
|
|
}
|
|
|
|
// Pure virtual methods have no actual symbol, so we can't generate
|
|
// something meaningful for them.
|
|
let is_dynamic_function = match self.kind() {
|
|
FunctionKind::Method(ref method_kind)
|
|
if method_kind.is_pure_virtual() =>
|
|
{
|
|
return None;
|
|
}
|
|
FunctionKind::Function => {
|
|
ctx.options().dynamic_library_name.is_some()
|
|
}
|
|
_ => false,
|
|
};
|
|
|
|
// Similar to static member variables in a class template, we can't
|
|
// generate bindings to template functions, because the set of
|
|
// instantiations is open ended and we have no way of knowing which
|
|
// monomorphizations actually exist.
|
|
if !item.all_template_params(ctx).is_empty() {
|
|
return None;
|
|
}
|
|
|
|
let name = self.name();
|
|
let mut canonical_name = item.canonical_name(ctx);
|
|
let mangled_name = self.mangled_name();
|
|
|
|
{
|
|
let seen_symbol_name = mangled_name.unwrap_or(&canonical_name);
|
|
|
|
// TODO: Maybe warn here if there's a type/argument mismatch, or
|
|
// something?
|
|
if result.seen_function(seen_symbol_name) {
|
|
return None;
|
|
}
|
|
result.saw_function(seen_symbol_name);
|
|
}
|
|
|
|
let mut attributes = vec![];
|
|
|
|
if ctx.options().rust_features().must_use_function {
|
|
let must_use = signature.must_use() || {
|
|
let ret_ty = signature
|
|
.return_type()
|
|
.into_resolver()
|
|
.through_type_refs()
|
|
.resolve(ctx);
|
|
ret_ty.must_use(ctx)
|
|
};
|
|
|
|
if must_use {
|
|
attributes.push(attributes::must_use());
|
|
}
|
|
}
|
|
|
|
if let Some(comment) = item.comment(ctx) {
|
|
attributes.push(attributes::doc(comment));
|
|
}
|
|
|
|
let abi = match signature.abi(ctx, Some(name)) {
|
|
Err(err) => {
|
|
if matches!(err, error::Error::UnsupportedAbi(_)) {
|
|
unsupported_abi_diagnostic(
|
|
name,
|
|
signature.is_variadic(),
|
|
item.location(),
|
|
ctx,
|
|
&err,
|
|
);
|
|
}
|
|
|
|
return None;
|
|
}
|
|
Ok(ClangAbi::Unknown(unknown_abi)) => {
|
|
panic!(
|
|
"Invalid or unknown abi {:?} for function {:?} ({:?})",
|
|
unknown_abi, canonical_name, self
|
|
);
|
|
}
|
|
Ok(abi) => abi,
|
|
};
|
|
|
|
// Handle overloaded functions by giving each overload its own unique
|
|
// suffix.
|
|
let times_seen = result.overload_number(&canonical_name);
|
|
if times_seen > 0 {
|
|
write!(&mut canonical_name, "{}", times_seen).unwrap();
|
|
}
|
|
|
|
let mut has_link_name_attr = false;
|
|
if let Some(link_name) = self.link_name() {
|
|
attributes.push(attributes::link_name::<false>(link_name));
|
|
has_link_name_attr = true;
|
|
} else {
|
|
let link_name = mangled_name.unwrap_or(name);
|
|
if !is_dynamic_function &&
|
|
!utils::names_will_be_identical_after_mangling(
|
|
&canonical_name,
|
|
link_name,
|
|
Some(abi),
|
|
)
|
|
{
|
|
attributes.push(attributes::link_name::<false>(link_name));
|
|
has_link_name_attr = true;
|
|
}
|
|
}
|
|
|
|
// Unfortunately this can't piggyback on the `attributes` list because
|
|
// the #[link(wasm_import_module)] needs to happen before the `extern
|
|
// "C"` block. It doesn't get picked up properly otherwise
|
|
let wasm_link_attribute =
|
|
ctx.options().wasm_import_module_name.as_ref().map(|name| {
|
|
quote! { #[link(wasm_import_module = #name)] }
|
|
});
|
|
|
|
let should_wrap =
|
|
is_internal && ctx.options().wrap_static_fns && !has_link_name_attr;
|
|
|
|
if should_wrap {
|
|
let name = canonical_name.clone() + ctx.wrap_static_fns_suffix();
|
|
attributes.push(attributes::link_name::<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 tokens = quote! {
|
|
#wasm_link_attribute
|
|
extern #abi {
|
|
#(#attributes)*
|
|
pub fn #ident ( #( #args ),* ) #ret;
|
|
}
|
|
};
|
|
|
|
// Add the item to the serialization list if necessary
|
|
if should_wrap {
|
|
result
|
|
.items_to_serialize
|
|
.push((item.id(), wrap_as_variadic));
|
|
}
|
|
|
|
// If we're doing dynamic binding generation, add to the dynamic items.
|
|
if is_dynamic_function {
|
|
let args_identifiers =
|
|
utils::fnsig_argument_identifiers(ctx, signature);
|
|
let ret_ty = utils::fnsig_return_ty(ctx, signature);
|
|
result.dynamic_items().push(
|
|
ident,
|
|
abi,
|
|
signature.is_variadic(),
|
|
ctx.options().dynamic_link_require_all,
|
|
args,
|
|
args_identifiers,
|
|
ret,
|
|
ret_ty,
|
|
attributes,
|
|
ctx,
|
|
);
|
|
} else {
|
|
result.push(tokens);
|
|
}
|
|
Some(times_seen)
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(not(feature = "experimental"), allow(unused_variables))]
|
|
fn unsupported_abi_diagnostic(
|
|
fn_name: &str,
|
|
variadic: bool,
|
|
location: Option<&crate::clang::SourceLocation>,
|
|
ctx: &BindgenContext,
|
|
error: &error::Error,
|
|
) {
|
|
warn!(
|
|
"Skipping {}function `{}` because the {}",
|
|
if variadic { "variadic " } else { "" },
|
|
fn_name,
|
|
error
|
|
);
|
|
|
|
#[cfg(feature = "experimental")]
|
|
if ctx.options().emit_diagnostics {
|
|
use crate::diagnostics::{get_line, Diagnostic, Level, Slice};
|
|
|
|
let mut diag = Diagnostic::default();
|
|
diag.with_title(
|
|
format!(
|
|
"Skipping {}function `{}` because the {}",
|
|
if variadic { "variadic " } else { "" },
|
|
fn_name,
|
|
error
|
|
),
|
|
Level::Warn,
|
|
)
|
|
.add_annotation(
|
|
"No code will be generated for this function.",
|
|
Level::Warn,
|
|
)
|
|
.add_annotation(
|
|
format!(
|
|
"The configured Rust version is {}.",
|
|
ctx.options().rust_target
|
|
),
|
|
Level::Note,
|
|
);
|
|
|
|
if let Some(loc) = location {
|
|
let (file, line, col, _) = loc.location();
|
|
|
|
if let Some(filename) = file.name() {
|
|
if let Ok(Some(source)) = get_line(&filename, line) {
|
|
let mut slice = Slice::default();
|
|
slice
|
|
.with_source(source)
|
|
.with_location(filename, line, col);
|
|
diag.add_slice(slice);
|
|
}
|
|
}
|
|
}
|
|
|
|
diag.display()
|
|
}
|
|
}
|
|
|
|
fn variadic_fn_diagnostic(
|
|
fn_name: &str,
|
|
_location: Option<&crate::clang::SourceLocation>,
|
|
_ctx: &BindgenContext,
|
|
) {
|
|
warn!(
|
|
"Cannot generate wrapper for the static variadic function `{}`.",
|
|
fn_name,
|
|
);
|
|
|
|
#[cfg(feature = "experimental")]
|
|
if _ctx.options().emit_diagnostics {
|
|
use crate::diagnostics::{get_line, Diagnostic, Level, Slice};
|
|
|
|
let mut diag = Diagnostic::default();
|
|
|
|
diag.with_title(format!("Cannot generate wrapper for the static function `{}`.", fn_name), Level::Warn)
|
|
.add_annotation("The `--wrap-static-fns` feature does not support variadic functions.", Level::Note)
|
|
.add_annotation("No code will be generated for this function.", Level::Note);
|
|
|
|
if let Some(loc) = _location {
|
|
let (file, line, col, _) = loc.location();
|
|
|
|
if let Some(filename) = file.name() {
|
|
if let Ok(Some(source)) = get_line(&filename, line) {
|
|
let mut slice = Slice::default();
|
|
slice
|
|
.with_source(source)
|
|
.with_location(filename, line, col);
|
|
diag.add_slice(slice);
|
|
}
|
|
}
|
|
}
|
|
|
|
diag.display()
|
|
}
|
|
}
|
|
|
|
fn objc_method_codegen(
|
|
ctx: &BindgenContext,
|
|
method: &ObjCMethod,
|
|
methods: &mut Vec<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.iter() {
|
|
protocol_set.insert(*protocol_id);
|
|
let protocol_name = ctx.rust_ident(
|
|
ctx.resolve_type(protocol_id.expect_type_id(ctx))
|
|
.name()
|
|
.unwrap(),
|
|
);
|
|
let impl_trait = quote! {
|
|
impl #protocol_name for #class_name { }
|
|
};
|
|
result.push(impl_trait);
|
|
}
|
|
let mut parent_class = self.parent_class;
|
|
while let Some(parent_id) = parent_class {
|
|
let parent = parent_id
|
|
.expect_type_id(ctx)
|
|
.into_resolver()
|
|
.through_type_refs()
|
|
.resolve(ctx)
|
|
.expect_type()
|
|
.kind();
|
|
|
|
let parent = match parent {
|
|
TypeKind::ObjCInterface(ref parent) => parent,
|
|
_ => break,
|
|
};
|
|
parent_class = parent.parent_class;
|
|
|
|
let parent_name = ctx.rust_ident(parent.rust_name());
|
|
let impl_trait = if parent.is_template() {
|
|
let template_names: Vec<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.iter() {
|
|
if protocol_set.insert(*protocol_id) {
|
|
let protocol_name = ctx.rust_ident(
|
|
ctx.resolve_type(protocol_id.expect_type_id(ctx))
|
|
.name()
|
|
.unwrap(),
|
|
);
|
|
let impl_trait = quote! {
|
|
impl #protocol_name for #class_name { }
|
|
};
|
|
result.push(impl_trait);
|
|
}
|
|
}
|
|
if !parent.is_template() {
|
|
let parent_struct_name = parent.name();
|
|
let child_struct_name = self.name();
|
|
let parent_struct = ctx.rust_ident(parent_struct_name);
|
|
let from_block = quote! {
|
|
impl From<#class_name> for #parent_struct {
|
|
fn from(child: #class_name) -> #parent_struct {
|
|
#parent_struct(child.0)
|
|
}
|
|
}
|
|
};
|
|
result.push(from_block);
|
|
|
|
let error_msg = format!(
|
|
"This {} cannot be downcasted to {}",
|
|
parent_struct_name, child_struct_name
|
|
);
|
|
let try_into_block = quote! {
|
|
impl std::convert::TryFrom<#parent_struct> for #class_name {
|
|
type Error = &'static str;
|
|
fn try_from(parent: #parent_struct) -> Result<#class_name, Self::Error> {
|
|
let is_kind_of : bool = unsafe { msg_send!(parent, isKindOfClass:class!(#class_name))};
|
|
if is_kind_of {
|
|
Ok(#class_name(parent.0))
|
|
} else {
|
|
Err(#error_msg)
|
|
}
|
|
}
|
|
}
|
|
};
|
|
result.push(try_into_block);
|
|
}
|
|
}
|
|
}
|
|
|
|
if !self.is_protocol() {
|
|
let impl_block = if self.is_template() {
|
|
let template_names: Vec<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::serialize::CSerialize;
|
|
use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque};
|
|
use crate::ir::context::BindgenContext;
|
|
use crate::ir::context::TypeId;
|
|
use crate::ir::function::{Abi, ClangAbi, FunctionSig};
|
|
use crate::ir::item::{Item, ItemCanonicalPath};
|
|
use crate::ir::ty::TypeKind;
|
|
use crate::{args_are_cpp, file_is_cpp};
|
|
use std::borrow::Cow;
|
|
use std::io::Write;
|
|
use std::mem;
|
|
use std::path::PathBuf;
|
|
use std::str::FromStr;
|
|
|
|
pub(super) fn serialize_items(
|
|
result: &CodegenResult,
|
|
context: &BindgenContext,
|
|
) -> Result<(), CodegenError> {
|
|
if result.items_to_serialize.is_empty() {
|
|
return Ok(());
|
|
}
|
|
|
|
let path = context
|
|
.options()
|
|
.wrap_static_fns_path
|
|
.as_ref()
|
|
.map(PathBuf::from)
|
|
.unwrap_or_else(|| {
|
|
std::env::temp_dir().join("bindgen").join("extern")
|
|
});
|
|
|
|
let dir = path.parent().unwrap();
|
|
|
|
if !dir.exists() {
|
|
std::fs::create_dir_all(dir)?;
|
|
}
|
|
|
|
let is_cpp = args_are_cpp(&context.options().clang_args) ||
|
|
context
|
|
.options()
|
|
.input_headers
|
|
.iter()
|
|
.any(|h| file_is_cpp(h));
|
|
|
|
let source_path = path.with_extension(if is_cpp { "cpp" } else { "c" });
|
|
|
|
let mut code = Vec::new();
|
|
|
|
if !context.options().input_headers.is_empty() {
|
|
for header in &context.options().input_headers {
|
|
writeln!(code, "#include \"{}\"", header)?;
|
|
}
|
|
|
|
writeln!(code)?;
|
|
}
|
|
|
|
if !context.options().input_header_contents.is_empty() {
|
|
for (name, contents) in &context.options().input_header_contents {
|
|
writeln!(code, "// {}\n{}", name, contents)?;
|
|
}
|
|
|
|
writeln!(code)?;
|
|
}
|
|
|
|
writeln!(code, "// Static wrappers\n")?;
|
|
|
|
for (id, wrap_as_variadic) in &result.items_to_serialize {
|
|
let item = context.resolve_item(*id);
|
|
item.serialize(context, wrap_as_variadic, &mut vec![], &mut code)?;
|
|
}
|
|
|
|
std::fs::write(source_path, code)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(super) fn wrap_as_variadic_fn(
|
|
ctx: &BindgenContext,
|
|
signature: &FunctionSig,
|
|
name: &str,
|
|
) -> Option<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>,
|
|
) {
|
|
let bitfield_unit_src = include_str!("./bitfield_unit.rs");
|
|
let bitfield_unit_src = if ctx.options().rust_features().min_const_fn {
|
|
Cow::Borrowed(bitfield_unit_src)
|
|
} else {
|
|
Cow::Owned(bitfield_unit_src.replace("const fn ", "fn "))
|
|
};
|
|
let bitfield_unit_type =
|
|
proc_macro2::TokenStream::from_str(&bitfield_unit_src).unwrap();
|
|
let bitfield_unit_type = quote!(#bitfield_unit_type);
|
|
|
|
let items = vec![bitfield_unit_type];
|
|
let old_items = mem::replace(result, items);
|
|
result.extend(old_items);
|
|
}
|
|
|
|
pub(crate) fn prepend_objc_header(
|
|
ctx: &BindgenContext,
|
|
result: &mut Vec<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();
|
|
|
|
// If the target supports `const fn`, declare eligible functions
|
|
// as `const fn` else just `fn`.
|
|
let const_fn = if ctx.options().rust_features().min_const_fn {
|
|
quote! { const fn }
|
|
} else {
|
|
quote! { fn }
|
|
};
|
|
|
|
// TODO(emilio): The fmt::Debug impl could be way nicer with
|
|
// std::intrinsics::type_name, but...
|
|
let union_field_decl = quote! {
|
|
#[repr(C)]
|
|
pub struct __BindgenUnionField<T>(::#prefix::marker::PhantomData<T>);
|
|
};
|
|
|
|
let transmute =
|
|
ctx.wrap_unsafe_ops(quote!(::#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 unsafe fn as_ref(&self) -> &T {
|
|
#transmute
|
|
}
|
|
|
|
#[inline]
|
|
pub unsafe fn as_mut(&mut self) -> &mut T {
|
|
#transmute
|
|
}
|
|
}
|
|
};
|
|
|
|
let union_field_default_impl = quote! {
|
|
impl<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 ctx.options().rust_features().min_const_fn {
|
|
quote! { const fn }
|
|
} else {
|
|
quote! { fn }
|
|
};
|
|
|
|
let incomplete_array_decl = quote! {
|
|
#[repr(C)]
|
|
#[derive(Default)]
|
|
pub struct __IncompleteArrayField<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 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())
|
|
}
|
|
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>, crate::ir::context::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 = match *name {
|
|
Some(ref name) => ctx.rust_mangle(name).into_owned(),
|
|
None => {
|
|
unnamed_arguments += 1;
|
|
format!("arg{}", unnamed_arguments)
|
|
}
|
|
};
|
|
|
|
assert!(!arg_name.is_empty());
|
|
let arg_name = ctx.rust_ident(arg_name);
|
|
|
|
quote! {
|
|
#arg_name : #arg_ty
|
|
}
|
|
})
|
|
.collect::<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 = match *name {
|
|
Some(ref name) => ctx.rust_mangle(name).into_owned(),
|
|
None => {
|
|
unnamed_arguments += 1;
|
|
format!("arg{}", unnamed_arguments)
|
|
}
|
|
};
|
|
|
|
assert!(!arg_name.is_empty());
|
|
let arg_name = ctx.rust_ident(arg_name);
|
|
|
|
quote! {
|
|
#arg_name
|
|
}
|
|
})
|
|
.collect::<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)) |
|
|
// None is the case for global variables
|
|
None => {
|
|
(b'_', false)
|
|
}
|
|
Some(ClangAbi::Known(Abi::Stdcall)) => (b'_', true),
|
|
Some(ClangAbi::Known(Abi::Fastcall)) => (b'@', true),
|
|
|
|
// This is something we don't recognize, stay on the safe side
|
|
// by emitting the `#[link_name]` attribute
|
|
Some(_) => return false,
|
|
};
|
|
|
|
// Check that the mangled name is long enough to at least contain the
|
|
// canonical name plus the expected prefix.
|
|
if mangled_name.len() < canonical_name.len() + 1 {
|
|
return false;
|
|
}
|
|
|
|
// Return if the mangled name does not start with the prefix expected
|
|
// for the given calling convention.
|
|
if mangled_name[0] != mangling_prefix {
|
|
return false;
|
|
}
|
|
|
|
// Check that the mangled name contains the canonical name after the
|
|
// prefix
|
|
if &mangled_name[1..canonical_name.len() + 1] != canonical_name {
|
|
return false;
|
|
}
|
|
|
|
// If the given calling convention also prescribes a suffix, check that
|
|
// it exists too
|
|
if expect_suffix {
|
|
let suffix = &mangled_name[canonical_name.len() + 1..];
|
|
|
|
// The shortest suffix is "@0"
|
|
if suffix.len() < 2 {
|
|
return false;
|
|
}
|
|
|
|
// Check that the suffix starts with '@' and is all ASCII decimals
|
|
// after that.
|
|
if suffix[0] != b'@' || !suffix[1..].iter().all(u8::is_ascii_digit)
|
|
{
|
|
return false;
|
|
}
|
|
} else if mangled_name.len() != canonical_name.len() + 1 {
|
|
// If we don't expect a prefix but there is one, we need the
|
|
// #[link_name] attribute
|
|
return false;
|
|
}
|
|
|
|
true
|
|
}
|
|
}
|