Skip to content

Use syn::Type instead of raw TokenStream. #2549

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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