Skip to content

Commit

Permalink
Use syn::Type instead of raw TokenStream. (#2549)
Browse files Browse the repository at this point in the history
  • Loading branch information
reitermarkus committed Jun 14, 2023
1 parent 38a2c93 commit bbeddb6
Show file tree
Hide file tree
Showing 6 changed files with 370 additions and 432 deletions.
15 changes: 12 additions & 3 deletions bindgen/codegen/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,26 @@ pub(crate) enum Error {
/// definition that is too difficult for us to understand (like a partial
/// template specialization).
InstantiationOfOpaqueType,

/// Function ABI is not supported.
UnsupportedAbi(&'static str),
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
Error::NoLayoutForOpaqueBlob => {
"Tried to generate an opaque blob, but had no layout"
"Tried to generate an opaque blob, but had no layout."
}
Error::InstantiationOfOpaqueType => {
"Instantiation of opaque template type or partial template \
specialization"
"Instantiation of opaque template type or partial template specialization."
}
Error::UnsupportedAbi(abi) => {
return write!(
f,
"{} ABI is not supported by the configured Rust target.",
abi
)
}
})
}
Expand Down
140 changes: 85 additions & 55 deletions bindgen/codegen/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

use crate::ir::context::BindgenContext;
use crate::ir::layout::Layout;
use proc_macro2::{Ident, Span, TokenStream};
use quote::TokenStreamExt;

pub(crate) mod attributes {
use proc_macro2::{Ident, Span, TokenStream};
Expand Down Expand Up @@ -79,114 +77,146 @@ pub(crate) mod attributes {

/// 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) -> TokenStream {
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_name = match opaque.known_rust_type_for_array(ctx) {
let ty = match opaque.known_rust_type_for_array(ctx) {
Some(ty) => ty,
None => {
warn!("Found unknown alignment on code generation!");
"u8"
syn::parse_quote! { u8 }
}
};

let ty_name = Ident::new(ty_name, Span::call_site());

let data_len = opaque.array_size(ctx).unwrap_or(layout.size);

if data_len == 1 {
quote! {
#ty_name
}
ty
} else {
quote! {
[ #ty_name ; #data_len ]
}
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<TokenStream> {
let name = Layout::known_type_for_size(ctx, layout.size)?;
let name = Ident::new(name, Span::call_site());
Some(quote! { #name })
) -> 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,
) -> TokenStream {
let mut tokens = quote! {};
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 {
tokens.append_all(quote! { root:: });
return syn::parse_quote! { root::#ty };
}

let size = layout.size;
tokens.append_all(quote! {
__BindgenBitfieldUnit<[u8; #size]>
});

tokens
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;
use crate::ir::ty::{FloatKind, IntKind};
use proc_macro2::{self, TokenStream};
use std::str::FromStr;

pub(crate) fn c_void(ctx: &BindgenContext) -> TokenStream {
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();
quote! {
#prefix::c_void
}
syn::parse_quote! { #prefix::c_void }
}
None => {
if ctx.options().use_core &&
ctx.options().rust_features.core_ffi_c_void
{
quote! { ::core::ffi::c_void }
syn::parse_quote! { ::core::ffi::c_void }
} else {
quote! { ::std::os::raw::c_void }
syn::parse_quote! { ::std::os::raw::c_void }
}
}
}
}

pub(crate) fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream {
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();
quote! {
#prefix::#ident
}
syn::parse_quote! { #prefix::#ident }
}
None => {
if ctx.options().use_core &&
ctx.options().rust_features().core_ffi_c
{
quote! {
::core::ffi::#ident
}
syn::parse_quote! { ::core::ffi::#ident }
} else {
quote! {
::std::os::raw::#ident
}
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] }
}
}
}
Expand All @@ -196,42 +226,42 @@ pub(crate) mod ast_ty {
ctx: &BindgenContext,
fk: FloatKind,
layout: Option<Layout>,
) -> TokenStream {
) -> 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::Float, true) => quote! { f32 },
(FloatKind::Double, true) => quote! { f64 },
(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 => quote! { f32 },
8 => quote! { f64 },
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(quote! { f64 }),
.unwrap_or(syn::parse_quote! { f64 }),
}
}
None => {
debug_assert!(
false,
"How didn't we know the layout for a primitive type?"
);
quote! { f64 }
syn::parse_quote! { f64 }
}
}
}
(FloatKind::Float128, _) => {
if ctx.options().rust_features.i128_and_u128 {
quote! { u128 }
syn::parse_quote! { u128 }
} else {
quote! { [u64; 2] }
syn::parse_quote! { [u64; 2] }
}
}
}
Expand Down
Loading

0 comments on commit bbeddb6

Please sign in to comment.