summaryrefslogtreecommitdiffstats
path: root/third_party/rust/bindgen/codegen/helpers.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/bindgen/codegen/helpers.rs')
-rw-r--r--third_party/rust/bindgen/codegen/helpers.rs355
1 files changed, 355 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/codegen/helpers.rs b/third_party/rust/bindgen/codegen/helpers.rs
new file mode 100644
index 0000000000..48bfe56dde
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/helpers.rs
@@ -0,0 +1,355 @@
+//! Helpers for code generation that don't need macro expansion.
+
+use crate::ir::context::BindgenContext;
+use crate::ir::layout::Layout;
+
+pub(crate) mod attributes {
+ use proc_macro2::{Ident, Span, TokenStream};
+ use std::{borrow::Cow, str::FromStr};
+
+ pub(crate) fn repr(which: &str) -> TokenStream {
+ let which = Ident::new(which, Span::call_site());
+ quote! {
+ #[repr( #which )]
+ }
+ }
+
+ pub(crate) fn repr_list(which_ones: &[&str]) -> TokenStream {
+ let which_ones = which_ones
+ .iter()
+ .cloned()
+ .map(|one| TokenStream::from_str(one).expect("repr to be valid"));
+ quote! {
+ #[repr( #( #which_ones ),* )]
+ }
+ }
+
+ pub(crate) fn derives(which_ones: &[&str]) -> TokenStream {
+ let which_ones = which_ones
+ .iter()
+ .cloned()
+ .map(|one| TokenStream::from_str(one).expect("derive to be valid"));
+ quote! {
+ #[derive( #( #which_ones ),* )]
+ }
+ }
+
+ pub(crate) fn inline() -> TokenStream {
+ quote! {
+ #[inline]
+ }
+ }
+
+ pub(crate) fn must_use() -> TokenStream {
+ quote! {
+ #[must_use]
+ }
+ }
+
+ pub(crate) fn non_exhaustive() -> TokenStream {
+ quote! {
+ #[non_exhaustive]
+ }
+ }
+
+ pub(crate) fn doc(comment: String) -> TokenStream {
+ if comment.is_empty() {
+ quote!()
+ } else {
+ quote!(#[doc = #comment])
+ }
+ }
+
+ pub(crate) fn link_name<const MANGLE: bool>(name: &str) -> TokenStream {
+ // LLVM mangles the name by default but it's already mangled.
+ // Prefixing the name with \u{1} should tell LLVM to not mangle it.
+ let name: Cow<'_, str> = if MANGLE {
+ name.into()
+ } else {
+ format!("\u{1}{}", name).into()
+ };
+
+ quote! {
+ #[link_name = #name]
+ }
+ }
+}
+
+/// Generates a proper type for a field or type with a given `Layout`, that is,
+/// a type with the correct size and alignment restrictions.
+pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> syn::Type {
+ let opaque = layout.opaque();
+
+ // FIXME(emilio, #412): We fall back to byte alignment, but there are
+ // some things that legitimately are more than 8-byte aligned.
+ //
+ // Eventually we should be able to `unwrap` here, but...
+ let ty = match opaque.known_rust_type_for_array(ctx) {
+ Some(ty) => ty,
+ None => {
+ warn!("Found unknown alignment on code generation!");
+ syn::parse_quote! { u8 }
+ }
+ };
+
+ let data_len = opaque.array_size(ctx).unwrap_or(layout.size);
+
+ if data_len == 1 {
+ ty
+ } else {
+ syn::parse_quote! { [ #ty ; #data_len ] }
+ }
+}
+
+/// Integer type of the same size as the given `Layout`.
+pub(crate) fn integer_type(
+ ctx: &BindgenContext,
+ layout: Layout,
+) -> Option<syn::Type> {
+ Layout::known_type_for_size(ctx, layout.size)
+}
+
+/// Generates a bitfield allocation unit type for a type with the given `Layout`.
+pub(crate) fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type {
+ let size = layout.size;
+ let ty = syn::parse_quote! { __BindgenBitfieldUnit<[u8; #size]> };
+
+ if ctx.options().enable_cxx_namespaces {
+ return syn::parse_quote! { root::#ty };
+ }
+
+ ty
+}
+
+pub(crate) mod ast_ty {
+ use crate::ir::context::BindgenContext;
+ use crate::ir::function::FunctionSig;
+ use crate::ir::layout::Layout;
+ use crate::ir::ty::{FloatKind, IntKind};
+ use proc_macro2::{self, TokenStream};
+ use std::str::FromStr;
+
+ pub(crate) fn c_void(ctx: &BindgenContext) -> syn::Type {
+ // ctypes_prefix takes precedence
+ match ctx.options().ctypes_prefix {
+ Some(ref prefix) => {
+ let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
+ syn::parse_quote! { #prefix::c_void }
+ }
+ None => {
+ if ctx.options().use_core &&
+ ctx.options().rust_features.core_ffi_c_void
+ {
+ syn::parse_quote! { ::core::ffi::c_void }
+ } else {
+ syn::parse_quote! { ::std::os::raw::c_void }
+ }
+ }
+ }
+ }
+
+ pub(crate) fn raw_type(ctx: &BindgenContext, name: &str) -> syn::Type {
+ let ident = ctx.rust_ident_raw(name);
+ match ctx.options().ctypes_prefix {
+ Some(ref prefix) => {
+ let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
+ syn::parse_quote! { #prefix::#ident }
+ }
+ None => {
+ if ctx.options().use_core &&
+ ctx.options().rust_features().core_ffi_c
+ {
+ syn::parse_quote! { ::core::ffi::#ident }
+ } else {
+ syn::parse_quote! { ::std::os::raw::#ident }
+ }
+ }
+ }
+ }
+
+ pub(crate) fn int_kind_rust_type(
+ ctx: &BindgenContext,
+ ik: IntKind,
+ layout: Option<Layout>,
+ ) -> syn::Type {
+ match ik {
+ IntKind::Bool => syn::parse_quote! { bool },
+ IntKind::Char { .. } => raw_type(ctx, "c_char"),
+ IntKind::SChar => raw_type(ctx, "c_schar"),
+ IntKind::UChar => raw_type(ctx, "c_uchar"),
+ IntKind::Short => raw_type(ctx, "c_short"),
+ IntKind::UShort => raw_type(ctx, "c_ushort"),
+ IntKind::Int => raw_type(ctx, "c_int"),
+ IntKind::UInt => raw_type(ctx, "c_uint"),
+ IntKind::Long => raw_type(ctx, "c_long"),
+ IntKind::ULong => raw_type(ctx, "c_ulong"),
+ IntKind::LongLong => raw_type(ctx, "c_longlong"),
+ IntKind::ULongLong => raw_type(ctx, "c_ulonglong"),
+ IntKind::WChar => {
+ let layout =
+ layout.expect("Couldn't compute wchar_t's layout?");
+ Layout::known_type_for_size(ctx, layout.size)
+ .expect("Non-representable wchar_t?")
+ }
+
+ IntKind::I8 => syn::parse_quote! { i8 },
+ IntKind::U8 => syn::parse_quote! { u8 },
+ IntKind::I16 => syn::parse_quote! { i16 },
+ IntKind::U16 => syn::parse_quote! { u16 },
+ IntKind::I32 => syn::parse_quote! { i32 },
+ IntKind::U32 => syn::parse_quote! { u32 },
+ IntKind::I64 => syn::parse_quote! { i64 },
+ IntKind::U64 => syn::parse_quote! { u64 },
+ IntKind::Custom { name, .. } => {
+ syn::parse_str(name).expect("Invalid integer type.")
+ }
+ IntKind::U128 => {
+ if ctx.options().rust_features.i128_and_u128 {
+ syn::parse_quote! { u128 }
+ } else {
+ // Best effort thing, but wrong alignment
+ // unfortunately.
+ syn::parse_quote! { [u64; 2] }
+ }
+ }
+ IntKind::I128 => {
+ if ctx.options().rust_features.i128_and_u128 {
+ syn::parse_quote! { i128 }
+ } else {
+ syn::parse_quote! { [u64; 2] }
+ }
+ }
+ }
+ }
+
+ pub(crate) fn float_kind_rust_type(
+ ctx: &BindgenContext,
+ fk: FloatKind,
+ layout: Option<Layout>,
+ ) -> syn::Type {
+ // TODO: we probably should take the type layout into account more
+ // often?
+ //
+ // Also, maybe this one shouldn't be the default?
+ match (fk, ctx.options().convert_floats) {
+ (FloatKind::Float16, _) => {
+ // TODO: do f16 when rust lands it
+ ctx.generated_bindgen_float16();
+ if ctx.options().enable_cxx_namespaces {
+ syn::parse_quote! { root::__BindgenFloat16 }
+ } else {
+ syn::parse_quote! { __BindgenFloat16 }
+ }
+ }
+ (FloatKind::Float, true) => syn::parse_quote! { f32 },
+ (FloatKind::Double, true) => syn::parse_quote! { f64 },
+ (FloatKind::Float, false) => raw_type(ctx, "c_float"),
+ (FloatKind::Double, false) => raw_type(ctx, "c_double"),
+ (FloatKind::LongDouble, _) => {
+ match layout {
+ Some(layout) => {
+ match layout.size {
+ 4 => syn::parse_quote! { f32 },
+ 8 => syn::parse_quote! { f64 },
+ // TODO(emilio): If rust ever gains f128 we should
+ // use it here and below.
+ _ => super::integer_type(ctx, layout)
+ .unwrap_or(syn::parse_quote! { f64 }),
+ }
+ }
+ None => {
+ debug_assert!(
+ false,
+ "How didn't we know the layout for a primitive type?"
+ );
+ syn::parse_quote! { f64 }
+ }
+ }
+ }
+ (FloatKind::Float128, _) => {
+ if ctx.options().rust_features.i128_and_u128 {
+ syn::parse_quote! { u128 }
+ } else {
+ syn::parse_quote! { [u64; 2] }
+ }
+ }
+ }
+ }
+
+ pub(crate) fn int_expr(val: i64) -> TokenStream {
+ // Don't use quote! { #val } because that adds the type suffix.
+ let val = proc_macro2::Literal::i64_unsuffixed(val);
+ quote!(#val)
+ }
+
+ pub(crate) fn uint_expr(val: u64) -> TokenStream {
+ // Don't use quote! { #val } because that adds the type suffix.
+ let val = proc_macro2::Literal::u64_unsuffixed(val);
+ quote!(#val)
+ }
+
+ pub(crate) fn cstr_expr(mut string: String) -> TokenStream {
+ string.push('\0');
+ let b = proc_macro2::Literal::byte_string(string.as_bytes());
+ quote! {
+ #b
+ }
+ }
+
+ pub(crate) fn float_expr(
+ ctx: &BindgenContext,
+ f: f64,
+ ) -> Result<TokenStream, ()> {
+ if f.is_finite() {
+ let val = proc_macro2::Literal::f64_unsuffixed(f);
+
+ return Ok(quote!(#val));
+ }
+
+ let prefix = ctx.trait_prefix();
+
+ if f.is_nan() {
+ return Ok(quote! {
+ ::#prefix::f64::NAN
+ });
+ }
+
+ if f.is_infinite() {
+ return Ok(if f.is_sign_positive() {
+ quote! {
+ ::#prefix::f64::INFINITY
+ }
+ } else {
+ quote! {
+ ::#prefix::f64::NEG_INFINITY
+ }
+ });
+ }
+
+ warn!("Unknown non-finite float number: {:?}", f);
+ Err(())
+ }
+
+ pub(crate) fn arguments_from_signature(
+ signature: &FunctionSig,
+ ctx: &BindgenContext,
+ ) -> Vec<TokenStream> {
+ let mut unnamed_arguments = 0;
+ signature
+ .argument_types()
+ .iter()
+ .map(|&(ref name, _ty)| match *name {
+ Some(ref name) => {
+ let name = ctx.rust_ident(name);
+ quote! { #name }
+ }
+ None => {
+ unnamed_arguments += 1;
+ let name =
+ ctx.rust_ident(format!("arg{}", unnamed_arguments));
+ quote! { #name }
+ }
+ })
+ .collect()
+ }
+}