1//! Helpers for code generation that don't need macro expansion.
2
3use crate::ir::context::BindgenContext;
4use crate::ir::layout::Layout;
5
6pub(crate) mod attributes {
7 use proc_macro2::{Ident, Span, TokenStream};
8 use std::{borrow::Cow, str::FromStr};
9
10 pub(crate) fn repr(which: &str) -> TokenStream {
11 let which = Ident::new(which, Span::call_site());
12 quote! {
13 #[repr( #which )]
14 }
15 }
16
17 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
27 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
37 pub(crate) fn inline() -> TokenStream {
38 quote! {
39 #[inline]
40 }
41 }
42
43 pub(crate) fn must_use() -> TokenStream {
44 quote! {
45 #[must_use]
46 }
47 }
48
49 pub(crate) fn non_exhaustive() -> TokenStream {
50 quote! {
51 #[non_exhaustive]
52 }
53 }
54
55 pub(crate) fn doc(comment: String) -> TokenStream {
56 if comment.is_empty() {
57 quote!()
58 } else {
59 quote!(#[doc = #comment])
60 }
61 }
62
63 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.
80pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> syn::Type {
81 let opaque: 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: Type = match opaque.known_rust_type_for_array(ctx) {
88 Some(ty: Type) => ty,
89 None => {
90 warn!("Found unknown alignment on code generation!");
91 syn::parse_quote! { u8 }
92 }
93 };
94
95 let data_len: usize = opaque.array_size(ctx).unwrap_or(default: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`.
105pub(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`.
113pub(crate) fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type {
114 let size: usize = layout.size;
115 let ty: Type = 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
124pub(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
132 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
151 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
170 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
225 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
279 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
285 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
291 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
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
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