1 //! Helpers for code generation that don't need macro expansion.
2 
3 use crate::ir::context::BindgenContext;
4 use crate::ir::layout::Layout;
5 
6 pub(crate) mod attributes {
7     use proc_macro2::{Ident, Span, TokenStream};
8     use std::{borrow::Cow, str::FromStr};
9 
repr(which: &str) -> TokenStream10     pub(crate) fn repr(which: &str) -> TokenStream {
11         let which = Ident::new(which, Span::call_site());
12         quote! {
13             #[repr( #which )]
14         }
15     }
16 
repr_list(which_ones: &[&str]) -> TokenStream17     pub(crate) fn repr_list(which_ones: &[&str]) -> TokenStream {
18         let which_ones = which_ones
19             .iter()
20             .cloned()
21             .map(|one| TokenStream::from_str(one).expect("repr to be valid"));
22         quote! {
23             #[repr( #( #which_ones ),* )]
24         }
25     }
26 
derives(which_ones: &[&str]) -> TokenStream27     pub(crate) fn derives(which_ones: &[&str]) -> TokenStream {
28         let which_ones = which_ones
29             .iter()
30             .cloned()
31             .map(|one| TokenStream::from_str(one).expect("derive to be valid"));
32         quote! {
33             #[derive( #( #which_ones ),* )]
34         }
35     }
36 
inline() -> TokenStream37     pub(crate) fn inline() -> TokenStream {
38         quote! {
39             #[inline]
40         }
41     }
42 
must_use() -> TokenStream43     pub(crate) fn must_use() -> TokenStream {
44         quote! {
45             #[must_use]
46         }
47     }
48 
non_exhaustive() -> TokenStream49     pub(crate) fn non_exhaustive() -> TokenStream {
50         quote! {
51             #[non_exhaustive]
52         }
53     }
54 
doc(comment: String) -> TokenStream55     pub(crate) fn doc(comment: String) -> TokenStream {
56         if comment.is_empty() {
57             quote!()
58         } else {
59             quote!(#[doc = #comment])
60         }
61     }
62 
link_name<const MANGLE: bool>(name: &str) -> TokenStream63     pub(crate) fn link_name<const MANGLE: bool>(name: &str) -> TokenStream {
64         // LLVM mangles the name by default but it's already mangled.
65         // Prefixing the name with \u{1} should tell LLVM to not mangle it.
66         let name: Cow<'_, str> = if MANGLE {
67             name.into()
68         } else {
69             format!("\u{1}{}", name).into()
70         };
71 
72         quote! {
73             #[link_name = #name]
74         }
75     }
76 }
77 
78 /// Generates a proper type for a field or type with a given `Layout`, that is,
79 /// a type with the correct size and alignment restrictions.
blob(ctx: &BindgenContext, layout: Layout) -> syn::Type80 pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> syn::Type {
81     let opaque = layout.opaque();
82 
83     // FIXME(emilio, #412): We fall back to byte alignment, but there are
84     // some things that legitimately are more than 8-byte aligned.
85     //
86     // Eventually we should be able to `unwrap` here, but...
87     let ty = match opaque.known_rust_type_for_array(ctx) {
88         Some(ty) => ty,
89         None => {
90             warn!("Found unknown alignment on code generation!");
91             syn::parse_quote! { u8 }
92         }
93     };
94 
95     let data_len = opaque.array_size(ctx).unwrap_or(layout.size);
96 
97     if data_len == 1 {
98         ty
99     } else {
100         syn::parse_quote! { [ #ty ; #data_len ] }
101     }
102 }
103 
104 /// Integer type of the same size as the given `Layout`.
integer_type( ctx: &BindgenContext, layout: Layout, ) -> Option<syn::Type>105 pub(crate) fn integer_type(
106     ctx: &BindgenContext,
107     layout: Layout,
108 ) -> Option<syn::Type> {
109     Layout::known_type_for_size(ctx, layout.size)
110 }
111 
112 /// Generates a bitfield allocation unit type for a type with the given `Layout`.
bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type113 pub(crate) fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type {
114     let size = layout.size;
115     let ty = syn::parse_quote! { __BindgenBitfieldUnit<[u8; #size]> };
116 
117     if ctx.options().enable_cxx_namespaces {
118         return syn::parse_quote! { root::#ty };
119     }
120 
121     ty
122 }
123 
124 pub(crate) mod ast_ty {
125     use crate::ir::context::BindgenContext;
126     use crate::ir::function::FunctionSig;
127     use crate::ir::layout::Layout;
128     use crate::ir::ty::{FloatKind, IntKind};
129     use proc_macro2::{self, TokenStream};
130     use std::str::FromStr;
131 
c_void(ctx: &BindgenContext) -> syn::Type132     pub(crate) fn c_void(ctx: &BindgenContext) -> syn::Type {
133         // ctypes_prefix takes precedence
134         match ctx.options().ctypes_prefix {
135             Some(ref prefix) => {
136                 let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
137                 syn::parse_quote! { #prefix::c_void }
138             }
139             None => {
140                 if ctx.options().use_core &&
141                     ctx.options().rust_features.core_ffi_c_void
142                 {
143                     syn::parse_quote! { ::core::ffi::c_void }
144                 } else {
145                     syn::parse_quote! { ::std::os::raw::c_void }
146                 }
147             }
148         }
149     }
150 
raw_type(ctx: &BindgenContext, name: &str) -> syn::Type151     pub(crate) fn raw_type(ctx: &BindgenContext, name: &str) -> syn::Type {
152         let ident = ctx.rust_ident_raw(name);
153         match ctx.options().ctypes_prefix {
154             Some(ref prefix) => {
155                 let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
156                 syn::parse_quote! { #prefix::#ident }
157             }
158             None => {
159                 if ctx.options().use_core &&
160                     ctx.options().rust_features().core_ffi_c
161                 {
162                     syn::parse_quote! { ::core::ffi::#ident }
163                 } else {
164                     syn::parse_quote! { ::std::os::raw::#ident }
165                 }
166             }
167         }
168     }
169 
int_kind_rust_type( ctx: &BindgenContext, ik: IntKind, layout: Option<Layout>, ) -> syn::Type170     pub(crate) fn int_kind_rust_type(
171         ctx: &BindgenContext,
172         ik: IntKind,
173         layout: Option<Layout>,
174     ) -> syn::Type {
175         match ik {
176             IntKind::Bool => syn::parse_quote! { bool },
177             IntKind::Char { .. } => raw_type(ctx, "c_char"),
178             IntKind::SChar => raw_type(ctx, "c_schar"),
179             IntKind::UChar => raw_type(ctx, "c_uchar"),
180             IntKind::Short => raw_type(ctx, "c_short"),
181             IntKind::UShort => raw_type(ctx, "c_ushort"),
182             IntKind::Int => raw_type(ctx, "c_int"),
183             IntKind::UInt => raw_type(ctx, "c_uint"),
184             IntKind::Long => raw_type(ctx, "c_long"),
185             IntKind::ULong => raw_type(ctx, "c_ulong"),
186             IntKind::LongLong => raw_type(ctx, "c_longlong"),
187             IntKind::ULongLong => raw_type(ctx, "c_ulonglong"),
188             IntKind::WChar => {
189                 let layout =
190                     layout.expect("Couldn't compute wchar_t's layout?");
191                 Layout::known_type_for_size(ctx, layout.size)
192                     .expect("Non-representable wchar_t?")
193             }
194 
195             IntKind::I8 => syn::parse_quote! { i8 },
196             IntKind::U8 => syn::parse_quote! { u8 },
197             IntKind::I16 => syn::parse_quote! { i16 },
198             IntKind::U16 => syn::parse_quote! { u16 },
199             IntKind::I32 => syn::parse_quote! { i32 },
200             IntKind::U32 => syn::parse_quote! { u32 },
201             IntKind::I64 => syn::parse_quote! { i64 },
202             IntKind::U64 => syn::parse_quote! { u64 },
203             IntKind::Custom { name, .. } => {
204                 syn::parse_str(name).expect("Invalid integer type.")
205             }
206             IntKind::U128 => {
207                 if ctx.options().rust_features.i128_and_u128 {
208                     syn::parse_quote! { u128 }
209                 } else {
210                     // Best effort thing, but wrong alignment
211                     // unfortunately.
212                     syn::parse_quote! { [u64; 2] }
213                 }
214             }
215             IntKind::I128 => {
216                 if ctx.options().rust_features.i128_and_u128 {
217                     syn::parse_quote! { i128 }
218                 } else {
219                     syn::parse_quote! { [u64; 2] }
220                 }
221             }
222         }
223     }
224 
float_kind_rust_type( ctx: &BindgenContext, fk: FloatKind, layout: Option<Layout>, ) -> syn::Type225     pub(crate) fn float_kind_rust_type(
226         ctx: &BindgenContext,
227         fk: FloatKind,
228         layout: Option<Layout>,
229     ) -> syn::Type {
230         // TODO: we probably should take the type layout into account more
231         // often?
232         //
233         // Also, maybe this one shouldn't be the default?
234         match (fk, ctx.options().convert_floats) {
235             (FloatKind::Float16, _) => {
236                 // TODO: do f16 when rust lands it
237                 ctx.generated_bindgen_float16();
238                 if ctx.options().enable_cxx_namespaces {
239                     syn::parse_quote! { root::__BindgenFloat16 }
240                 } else {
241                     syn::parse_quote! { __BindgenFloat16 }
242                 }
243             }
244             (FloatKind::Float, true) => syn::parse_quote! { f32 },
245             (FloatKind::Double, true) => syn::parse_quote! { f64 },
246             (FloatKind::Float, false) => raw_type(ctx, "c_float"),
247             (FloatKind::Double, false) => raw_type(ctx, "c_double"),
248             (FloatKind::LongDouble, _) => {
249                 match layout {
250                     Some(layout) => {
251                         match layout.size {
252                             4 => syn::parse_quote! { f32 },
253                             8 => syn::parse_quote! { f64 },
254                             // TODO(emilio): If rust ever gains f128 we should
255                             // use it here and below.
256                             _ => super::integer_type(ctx, layout)
257                                 .unwrap_or(syn::parse_quote! { f64 }),
258                         }
259                     }
260                     None => {
261                         debug_assert!(
262                             false,
263                             "How didn't we know the layout for a primitive type?"
264                         );
265                         syn::parse_quote! { f64 }
266                     }
267                 }
268             }
269             (FloatKind::Float128, _) => {
270                 if ctx.options().rust_features.i128_and_u128 {
271                     syn::parse_quote! { u128 }
272                 } else {
273                     syn::parse_quote! { [u64; 2] }
274                 }
275             }
276         }
277     }
278 
int_expr(val: i64) -> TokenStream279     pub(crate) fn int_expr(val: i64) -> TokenStream {
280         // Don't use quote! { #val } because that adds the type suffix.
281         let val = proc_macro2::Literal::i64_unsuffixed(val);
282         quote!(#val)
283     }
284 
uint_expr(val: u64) -> TokenStream285     pub(crate) fn uint_expr(val: u64) -> TokenStream {
286         // Don't use quote! { #val } because that adds the type suffix.
287         let val = proc_macro2::Literal::u64_unsuffixed(val);
288         quote!(#val)
289     }
290 
cstr_expr(mut string: String) -> TokenStream291     pub(crate) fn cstr_expr(mut string: String) -> TokenStream {
292         string.push('\0');
293         let b = proc_macro2::Literal::byte_string(string.as_bytes());
294         quote! {
295             #b
296         }
297     }
298 
float_expr( ctx: &BindgenContext, f: f64, ) -> Result<TokenStream, ()>299     pub(crate) fn float_expr(
300         ctx: &BindgenContext,
301         f: f64,
302     ) -> Result<TokenStream, ()> {
303         if f.is_finite() {
304             let val = proc_macro2::Literal::f64_unsuffixed(f);
305 
306             return Ok(quote!(#val));
307         }
308 
309         let prefix = ctx.trait_prefix();
310 
311         if f.is_nan() {
312             return Ok(quote! {
313                 ::#prefix::f64::NAN
314             });
315         }
316 
317         if f.is_infinite() {
318             return Ok(if f.is_sign_positive() {
319                 quote! {
320                     ::#prefix::f64::INFINITY
321                 }
322             } else {
323                 quote! {
324                     ::#prefix::f64::NEG_INFINITY
325                 }
326             });
327         }
328 
329         warn!("Unknown non-finite float number: {:?}", f);
330         Err(())
331     }
332 
arguments_from_signature( signature: &FunctionSig, ctx: &BindgenContext, ) -> Vec<TokenStream>333     pub(crate) fn arguments_from_signature(
334         signature: &FunctionSig,
335         ctx: &BindgenContext,
336     ) -> Vec<TokenStream> {
337         let mut unnamed_arguments = 0;
338         signature
339             .argument_types()
340             .iter()
341             .map(|&(ref name, _ty)| match *name {
342                 Some(ref name) => {
343                     let name = ctx.rust_ident(name);
344                     quote! { #name }
345                 }
346                 None => {
347                     unnamed_arguments += 1;
348                     let name =
349                         ctx.rust_ident(format!("arg{}", unnamed_arguments));
350                     quote! { #name }
351                 }
352             })
353             .collect()
354     }
355 }
356