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