xref: /third_party/rust/crates/cxx/macro/src/expand.rs (revision 33d722a9)
1use crate::syntax::atom::Atom::*;
2use crate::syntax::attrs::{self, OtherAttrs};
3use crate::syntax::cfg::CfgExpr;
4use crate::syntax::file::Module;
5use crate::syntax::instantiate::{ImplKey, NamedImplKey};
6use crate::syntax::qualified::QualifiedName;
7use crate::syntax::report::Errors;
8use crate::syntax::symbol::Symbol;
9use crate::syntax::{
10    self, check, mangle, Api, Doc, Enum, ExternFn, ExternType, Impl, Lifetimes, Pair, Signature,
11    Struct, Trait, Type, TypeAlias, Types,
12};
13use crate::type_id::Crate;
14use crate::{derive, generics};
15use proc_macro2::{Ident, Span, TokenStream};
16use quote::{format_ident, quote, quote_spanned, ToTokens};
17use std::mem;
18use syn::{parse_quote, punctuated, Generics, Lifetime, Result, Token};
19
20pub fn bridge(mut ffi: Module) -> Result<TokenStream> {
21    let ref mut errors = Errors::new();
22
23    let mut cfg = CfgExpr::Unconditional;
24    let mut doc = Doc::new();
25    let attrs = attrs::parse(
26        errors,
27        mem::take(&mut ffi.attrs),
28        attrs::Parser {
29            cfg: Some(&mut cfg),
30            doc: Some(&mut doc),
31            ..Default::default()
32        },
33    );
34
35    let content = mem::take(&mut ffi.content);
36    let trusted = ffi.unsafety.is_some();
37    let namespace = &ffi.namespace;
38    let ref mut apis = syntax::parse_items(errors, content, trusted, namespace);
39    #[cfg(feature = "experimental-enum-variants-from-header")]
40    crate::load::load(errors, apis);
41    let ref types = Types::collect(errors, apis);
42    errors.propagate()?;
43
44    let generator = check::Generator::Macro;
45    check::typecheck(errors, apis, types, generator);
46    errors.propagate()?;
47
48    Ok(expand(ffi, doc, attrs, apis, types))
49}
50
51fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types) -> TokenStream {
52    let mut expanded = TokenStream::new();
53    let mut hidden = TokenStream::new();
54    let mut forbid = TokenStream::new();
55
56    for api in apis {
57        if let Api::RustType(ety) = api {
58            expanded.extend(expand_rust_type_import(ety));
59            hidden.extend(expand_rust_type_assert_unpin(ety, types));
60        }
61    }
62
63    for api in apis {
64        match api {
65            Api::Include(_) | Api::Impl(_) => {}
66            Api::Struct(strct) => {
67                expanded.extend(expand_struct(strct));
68                hidden.extend(expand_struct_operators(strct));
69                forbid.extend(expand_struct_forbid_drop(strct));
70            }
71            Api::Enum(enm) => expanded.extend(expand_enum(enm)),
72            Api::CxxType(ety) => {
73                let ident = &ety.name.rust;
74                if !types.structs.contains_key(ident) && !types.enums.contains_key(ident) {
75                    expanded.extend(expand_cxx_type(ety));
76                    hidden.extend(expand_cxx_type_assert_pinned(ety, types));
77                }
78            }
79            Api::CxxFunction(efn) => {
80                expanded.extend(expand_cxx_function_shim(efn, types));
81            }
82            Api::RustType(ety) => {
83                expanded.extend(expand_rust_type_impl(ety));
84                hidden.extend(expand_rust_type_layout(ety, types));
85            }
86            Api::RustFunction(efn) => hidden.extend(expand_rust_function_shim(efn, types)),
87            Api::TypeAlias(alias) => {
88                expanded.extend(expand_type_alias(alias));
89                hidden.extend(expand_type_alias_verify(alias, types));
90            }
91        }
92    }
93
94    for (impl_key, &explicit_impl) in &types.impls {
95        match *impl_key {
96            ImplKey::RustBox(ident) => {
97                hidden.extend(expand_rust_box(ident, types, explicit_impl));
98            }
99            ImplKey::RustVec(ident) => {
100                hidden.extend(expand_rust_vec(ident, types, explicit_impl));
101            }
102            ImplKey::UniquePtr(ident) => {
103                expanded.extend(expand_unique_ptr(ident, types, explicit_impl));
104            }
105            ImplKey::SharedPtr(ident) => {
106                expanded.extend(expand_shared_ptr(ident, types, explicit_impl));
107            }
108            ImplKey::WeakPtr(ident) => {
109                expanded.extend(expand_weak_ptr(ident, types, explicit_impl));
110            }
111            ImplKey::CxxVector(ident) => {
112                expanded.extend(expand_cxx_vector(ident, explicit_impl, types));
113            }
114        }
115    }
116
117    if !forbid.is_empty() {
118        hidden.extend(expand_forbid(forbid));
119    }
120
121    // Work around https://github.com/rust-lang/rust/issues/67851.
122    if !hidden.is_empty() {
123        expanded.extend(quote! {
124            #[doc(hidden)]
125            const _: () = {
126                #hidden
127            };
128        });
129    }
130
131    let vis = &ffi.vis;
132    let mod_token = &ffi.mod_token;
133    let ident = &ffi.ident;
134    let span = ffi.brace_token.span;
135    let expanded = quote_spanned!(span=> {#expanded});
136
137    quote! {
138        #doc
139        #attrs
140        #[deny(improper_ctypes, improper_ctypes_definitions)]
141        #[allow(clippy::unknown_clippy_lints)]
142        #[allow(
143            non_camel_case_types,
144            non_snake_case,
145            clippy::extra_unused_type_parameters,
146            clippy::ptr_as_ptr,
147            clippy::upper_case_acronyms,
148            clippy::use_self,
149        )]
150        #vis #mod_token #ident #expanded
151    }
152}
153
154fn expand_struct(strct: &Struct) -> TokenStream {
155    let ident = &strct.name.rust;
156    let doc = &strct.doc;
157    let attrs = &strct.attrs;
158    let generics = &strct.generics;
159    let type_id = type_id(&strct.name);
160    let fields = strct.fields.iter().map(|field| {
161        let doc = &field.doc;
162        let attrs = &field.attrs;
163        // This span on the pub makes "private type in public interface" errors
164        // appear in the right place.
165        let vis = field.visibility;
166        quote!(#doc #attrs #vis #field)
167    });
168    let mut derives = None;
169    let derived_traits = derive::expand_struct(strct, &mut derives);
170
171    let span = ident.span();
172    let visibility = strct.visibility;
173    let struct_token = strct.struct_token;
174    let struct_def = quote_spanned! {span=>
175        #visibility #struct_token #ident #generics {
176            #(#fields,)*
177        }
178    };
179
180    quote! {
181        #doc
182        #derives
183        #attrs
184        #[repr(C)]
185        #struct_def
186
187        unsafe impl #generics ::cxx::ExternType for #ident #generics {
188            #[allow(unused_attributes)] // incorrect lint
189            #[doc(hidden)]
190            type Id = #type_id;
191            type Kind = ::cxx::kind::Trivial;
192        }
193
194        #derived_traits
195    }
196}
197
198fn expand_struct_operators(strct: &Struct) -> TokenStream {
199    let ident = &strct.name.rust;
200    let generics = &strct.generics;
201    let mut operators = TokenStream::new();
202
203    for derive in &strct.derives {
204        let span = derive.span;
205        match derive.what {
206            Trait::PartialEq => {
207                let link_name = mangle::operator(&strct.name, "eq");
208                let local_name = format_ident!("__operator_eq_{}", strct.name.rust);
209                let prevent_unwind_label = format!("::{} as PartialEq>::eq", strct.name.rust);
210                operators.extend(quote_spanned! {span=>
211                    #[doc(hidden)]
212                    #[export_name = #link_name]
213                    extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
214                        let __fn = concat!("<", module_path!(), #prevent_unwind_label);
215                        ::cxx::private::prevent_unwind(__fn, || *lhs == *rhs)
216                    }
217                });
218
219                if !derive::contains(&strct.derives, Trait::Eq) {
220                    let link_name = mangle::operator(&strct.name, "ne");
221                    let local_name = format_ident!("__operator_ne_{}", strct.name.rust);
222                    let prevent_unwind_label = format!("::{} as PartialEq>::ne", strct.name.rust);
223                    operators.extend(quote_spanned! {span=>
224                        #[doc(hidden)]
225                        #[export_name = #link_name]
226                        extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
227                            let __fn = concat!("<", module_path!(), #prevent_unwind_label);
228                            ::cxx::private::prevent_unwind(__fn, || *lhs != *rhs)
229                        }
230                    });
231                }
232            }
233            Trait::PartialOrd => {
234                let link_name = mangle::operator(&strct.name, "lt");
235                let local_name = format_ident!("__operator_lt_{}", strct.name.rust);
236                let prevent_unwind_label = format!("::{} as PartialOrd>::lt", strct.name.rust);
237                operators.extend(quote_spanned! {span=>
238                    #[doc(hidden)]
239                    #[export_name = #link_name]
240                    extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
241                        let __fn = concat!("<", module_path!(), #prevent_unwind_label);
242                        ::cxx::private::prevent_unwind(__fn, || *lhs < *rhs)
243                    }
244                });
245
246                let link_name = mangle::operator(&strct.name, "le");
247                let local_name = format_ident!("__operator_le_{}", strct.name.rust);
248                let prevent_unwind_label = format!("::{} as PartialOrd>::le", strct.name.rust);
249                operators.extend(quote_spanned! {span=>
250                    #[doc(hidden)]
251                    #[export_name = #link_name]
252                    extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
253                        let __fn = concat!("<", module_path!(), #prevent_unwind_label);
254                        ::cxx::private::prevent_unwind(__fn, || *lhs <= *rhs)
255                    }
256                });
257
258                if !derive::contains(&strct.derives, Trait::Ord) {
259                    let link_name = mangle::operator(&strct.name, "gt");
260                    let local_name = format_ident!("__operator_gt_{}", strct.name.rust);
261                    let prevent_unwind_label = format!("::{} as PartialOrd>::gt", strct.name.rust);
262                    operators.extend(quote_spanned! {span=>
263                        #[doc(hidden)]
264                        #[export_name = #link_name]
265                        extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
266                            let __fn = concat!("<", module_path!(), #prevent_unwind_label);
267                            ::cxx::private::prevent_unwind(__fn, || *lhs > *rhs)
268                        }
269                    });
270
271                    let link_name = mangle::operator(&strct.name, "ge");
272                    let local_name = format_ident!("__operator_ge_{}", strct.name.rust);
273                    let prevent_unwind_label = format!("::{} as PartialOrd>::ge", strct.name.rust);
274                    operators.extend(quote_spanned! {span=>
275                        #[doc(hidden)]
276                        #[export_name = #link_name]
277                        extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
278                            let __fn = concat!("<", module_path!(), #prevent_unwind_label);
279                            ::cxx::private::prevent_unwind(__fn, || *lhs >= *rhs)
280                        }
281                    });
282                }
283            }
284            Trait::Hash => {
285                let link_name = mangle::operator(&strct.name, "hash");
286                let local_name = format_ident!("__operator_hash_{}", strct.name.rust);
287                let prevent_unwind_label = format!("::{} as Hash>::hash", strct.name.rust);
288                operators.extend(quote_spanned! {span=>
289                    #[doc(hidden)]
290                    #[export_name = #link_name]
291                    #[allow(clippy::cast_possible_truncation)]
292                    extern "C" fn #local_name #generics(this: &#ident #generics) -> usize {
293                        let __fn = concat!("<", module_path!(), #prevent_unwind_label);
294                        ::cxx::private::prevent_unwind(__fn, || ::cxx::private::hash(this))
295                    }
296                });
297            }
298            _ => {}
299        }
300    }
301
302    operators
303}
304
305fn expand_struct_forbid_drop(strct: &Struct) -> TokenStream {
306    let ident = &strct.name.rust;
307    let generics = &strct.generics;
308    let span = ident.span();
309    let impl_token = Token![impl](strct.visibility.span);
310
311    quote_spanned! {span=>
312        #impl_token #generics self::Drop for super::#ident #generics {}
313    }
314}
315
316fn expand_enum(enm: &Enum) -> TokenStream {
317    let ident = &enm.name.rust;
318    let doc = &enm.doc;
319    let attrs = &enm.attrs;
320    let repr = &enm.repr;
321    let type_id = type_id(&enm.name);
322    let variants = enm.variants.iter().map(|variant| {
323        let doc = &variant.doc;
324        let attrs = &variant.attrs;
325        let variant_ident = &variant.name.rust;
326        let discriminant = &variant.discriminant;
327        let span = variant_ident.span();
328        Some(quote_spanned! {span=>
329            #doc
330            #attrs
331            #[allow(dead_code)]
332            pub const #variant_ident: Self = #ident { repr: #discriminant };
333        })
334    });
335    let mut derives = None;
336    let derived_traits = derive::expand_enum(enm, &mut derives);
337
338    let span = ident.span();
339    let visibility = enm.visibility;
340    let struct_token = Token![struct](enm.enum_token.span);
341    let enum_repr = quote! {
342        #[allow(missing_docs)]
343        pub repr: #repr,
344    };
345    let enum_def = quote_spanned! {span=>
346        #visibility #struct_token #ident {
347            #enum_repr
348        }
349    };
350
351    quote! {
352        #doc
353        #derives
354        #attrs
355        #[repr(transparent)]
356        #enum_def
357
358        #[allow(non_upper_case_globals)]
359        impl #ident {
360            #(#variants)*
361        }
362
363        unsafe impl ::cxx::ExternType for #ident {
364            #[allow(unused_attributes)] // incorrect lint
365            #[doc(hidden)]
366            type Id = #type_id;
367            type Kind = ::cxx::kind::Trivial;
368        }
369
370        #derived_traits
371    }
372}
373
374fn expand_cxx_type(ety: &ExternType) -> TokenStream {
375    let ident = &ety.name.rust;
376    let doc = &ety.doc;
377    let attrs = &ety.attrs;
378    let generics = &ety.generics;
379    let type_id = type_id(&ety.name);
380
381    let lifetime_fields = ety.generics.lifetimes.iter().map(|lifetime| {
382        let field = format_ident!("_lifetime_{}", lifetime.ident);
383        quote!(#field: ::cxx::core::marker::PhantomData<&#lifetime ()>)
384    });
385    let repr_fields = quote! {
386        _private: ::cxx::private::Opaque,
387        #(#lifetime_fields,)*
388    };
389
390    let span = ident.span();
391    let visibility = &ety.visibility;
392    let struct_token = Token![struct](ety.type_token.span);
393    let extern_type_def = quote_spanned! {span=>
394        #visibility #struct_token #ident #generics {
395            #repr_fields
396        }
397    };
398
399    quote! {
400        #doc
401        #attrs
402        #[repr(C)]
403        #extern_type_def
404
405        unsafe impl #generics ::cxx::ExternType for #ident #generics {
406            #[allow(unused_attributes)] // incorrect lint
407            #[doc(hidden)]
408            type Id = #type_id;
409            type Kind = ::cxx::kind::Opaque;
410        }
411    }
412}
413
414fn expand_cxx_type_assert_pinned(ety: &ExternType, types: &Types) -> TokenStream {
415    let ident = &ety.name.rust;
416    let infer = Token![_](ident.span());
417
418    let resolve = types.resolve(ident);
419    let lifetimes = resolve.generics.to_underscore_lifetimes();
420
421    quote! {
422        let _: fn() = {
423            // Derived from https://github.com/nvzqz/static-assertions-rs.
424            trait __AmbiguousIfImpl<A> {
425                fn infer() {}
426            }
427
428            impl<T> __AmbiguousIfImpl<()> for T
429            where
430                T: ?::cxx::core::marker::Sized
431            {}
432
433            #[allow(dead_code)]
434            struct __Invalid;
435
436            impl<T> __AmbiguousIfImpl<__Invalid> for T
437            where
438                T: ?::cxx::core::marker::Sized + ::cxx::core::marker::Unpin,
439            {}
440
441            // If there is only one specialized trait impl, type inference with
442            // `_` can be resolved and this can compile. Fails to compile if
443            // user has added a manual Unpin impl for their opaque C++ type as
444            // then `__AmbiguousIfImpl<__Invalid>` also exists.
445            <#ident #lifetimes as __AmbiguousIfImpl<#infer>>::infer
446        };
447    }
448}
449
450fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream {
451    let generics = &efn.generics;
452    let receiver = efn.receiver.iter().map(|receiver| {
453        let receiver_type = receiver.ty();
454        quote!(_: #receiver_type)
455    });
456    let args = efn.args.iter().map(|arg| {
457        let var = &arg.name.rust;
458        let colon = arg.colon_token;
459        let ty = expand_extern_type(&arg.ty, types, true);
460        if arg.ty == RustString {
461            quote!(#var #colon *const #ty)
462        } else if let Type::RustVec(_) = arg.ty {
463            quote!(#var #colon *const #ty)
464        } else if let Type::Fn(_) = arg.ty {
465            quote!(#var #colon ::cxx::private::FatFunction)
466        } else if types.needs_indirect_abi(&arg.ty) {
467            quote!(#var #colon *mut #ty)
468        } else {
469            quote!(#var #colon #ty)
470        }
471    });
472    let all_args = receiver.chain(args);
473    let ret = if efn.throws {
474        quote!(-> ::cxx::private::Result)
475    } else {
476        expand_extern_return_type(&efn.ret, types, true)
477    };
478    let mut outparam = None;
479    if indirect_return(efn, types) {
480        let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
481        outparam = Some(quote!(__return: *mut #ret));
482    }
483    let link_name = mangle::extern_fn(efn, types);
484    let local_name = format_ident!("__{}", efn.name.rust);
485    quote! {
486        #[link_name = #link_name]
487        fn #local_name #generics(#(#all_args,)* #outparam) #ret;
488    }
489}
490
491fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
492    let doc = &efn.doc;
493    let attrs = &efn.attrs;
494    let decl = expand_cxx_function_decl(efn, types);
495    let receiver = efn.receiver.iter().map(|receiver| {
496        let var = receiver.var;
497        if receiver.pinned {
498            let colon = receiver.colon_token;
499            let ty = receiver.ty_self();
500            quote!(#var #colon #ty)
501        } else {
502            let ampersand = receiver.ampersand;
503            let lifetime = &receiver.lifetime;
504            let mutability = receiver.mutability;
505            quote!(#ampersand #lifetime #mutability #var)
506        }
507    });
508    let args = efn.args.iter().map(|arg| quote!(#arg));
509    let all_args = receiver.chain(args);
510    let ret = if efn.throws {
511        let ok = match &efn.ret {
512            Some(ret) => quote!(#ret),
513            None => quote!(()),
514        };
515        quote!(-> ::cxx::core::result::Result<#ok, ::cxx::Exception>)
516    } else {
517        expand_return_type(&efn.ret)
518    };
519    let indirect_return = indirect_return(efn, types);
520    let receiver_var = efn
521        .receiver
522        .iter()
523        .map(|receiver| receiver.var.to_token_stream());
524    let arg_vars = efn.args.iter().map(|arg| {
525        let var = &arg.name.rust;
526        let span = var.span();
527        match &arg.ty {
528            Type::Ident(ident) if ident.rust == RustString => {
529                quote_spanned!(span=> #var.as_mut_ptr() as *const ::cxx::private::RustString)
530            }
531            Type::RustBox(ty) => {
532                if types.is_considered_improper_ctype(&ty.inner) {
533                    quote_spanned!(span=> ::cxx::alloc::boxed::Box::into_raw(#var).cast())
534                } else {
535                    quote_spanned!(span=> ::cxx::alloc::boxed::Box::into_raw(#var))
536                }
537            }
538            Type::UniquePtr(ty) => {
539                if types.is_considered_improper_ctype(&ty.inner) {
540                    quote_spanned!(span=> ::cxx::UniquePtr::into_raw(#var).cast())
541                } else {
542                    quote_spanned!(span=> ::cxx::UniquePtr::into_raw(#var))
543                }
544            }
545            Type::RustVec(_) => quote_spanned!(span=> #var.as_mut_ptr() as *const ::cxx::private::RustVec<_>),
546            Type::Ref(ty) => match &ty.inner {
547                Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
548                    false => quote_spanned!(span=> ::cxx::private::RustString::from_ref(#var)),
549                    true => quote_spanned!(span=> ::cxx::private::RustString::from_mut(#var)),
550                },
551                Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
552                    false => quote_spanned!(span=> ::cxx::private::RustVec::from_ref_vec_string(#var)),
553                    true => quote_spanned!(span=> ::cxx::private::RustVec::from_mut_vec_string(#var)),
554                },
555                Type::RustVec(_) => match ty.mutable {
556                    false => quote_spanned!(span=> ::cxx::private::RustVec::from_ref(#var)),
557                    true => quote_spanned!(span=> ::cxx::private::RustVec::from_mut(#var)),
558                },
559                inner if types.is_considered_improper_ctype(inner) => {
560                    let var = match ty.pinned {
561                        false => quote!(#var),
562                        true => quote_spanned!(span=> ::cxx::core::pin::Pin::into_inner_unchecked(#var)),
563                    };
564                    match ty.mutable {
565                        false => {
566                            quote_spanned!(span=> #var as *const #inner as *const ::cxx::core::ffi::c_void)
567                        }
568                        true => quote_spanned!(span=> #var as *mut #inner as *mut ::cxx::core::ffi::c_void),
569                    }
570                }
571                _ => quote!(#var),
572            },
573            Type::Ptr(ty) => {
574                if types.is_considered_improper_ctype(&ty.inner) {
575                    quote_spanned!(span=> #var.cast())
576                } else {
577                    quote!(#var)
578                }
579            }
580            Type::Str(_) => quote_spanned!(span=> ::cxx::private::RustStr::from(#var)),
581            Type::SliceRef(ty) => match ty.mutable {
582                false => quote_spanned!(span=> ::cxx::private::RustSlice::from_ref(#var)),
583                true => quote_spanned!(span=> ::cxx::private::RustSlice::from_mut(#var)),
584            },
585            ty if types.needs_indirect_abi(ty) => quote_spanned!(span=> #var.as_mut_ptr()),
586            _ => quote!(#var),
587        }
588    });
589    let vars = receiver_var.chain(arg_vars);
590    let trampolines = efn
591        .args
592        .iter()
593        .filter_map(|arg| {
594            if let Type::Fn(f) = &arg.ty {
595                let var = &arg.name;
596                Some(expand_function_pointer_trampoline(efn, var, f, types))
597            } else {
598                None
599            }
600        })
601        .collect::<TokenStream>();
602    let mut setup = efn
603        .args
604        .iter()
605        .filter(|arg| types.needs_indirect_abi(&arg.ty))
606        .map(|arg| {
607            let var = &arg.name.rust;
608            let span = var.span();
609            // These are arguments for which C++ has taken ownership of the data
610            // behind the mut reference it received.
611            quote_spanned! {span=>
612                let mut #var = ::cxx::core::mem::MaybeUninit::new(#var);
613            }
614        })
615        .collect::<TokenStream>();
616    let local_name = format_ident!("__{}", efn.name.rust);
617    let span = efn.semi_token.span;
618    let call = if indirect_return {
619        let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
620        setup.extend(quote_spanned! {span=>
621            let mut __return = ::cxx::core::mem::MaybeUninit::<#ret>::uninit();
622        });
623        setup.extend(if efn.throws {
624            quote_spanned! {span=>
625                #local_name(#(#vars,)* __return.as_mut_ptr()).exception()?;
626            }
627        } else {
628            quote_spanned! {span=>
629                #local_name(#(#vars,)* __return.as_mut_ptr());
630            }
631        });
632        quote_spanned!(span=> __return.assume_init())
633    } else if efn.throws {
634        quote_spanned! {span=>
635            #local_name(#(#vars),*).exception()
636        }
637    } else {
638        quote_spanned! {span=>
639            #local_name(#(#vars),*)
640        }
641    };
642    let mut expr;
643    if efn.throws && efn.sig.ret.is_none() {
644        expr = call;
645    } else {
646        expr = match &efn.ret {
647            None => call,
648            Some(ret) => match ret {
649                Type::Ident(ident) if ident.rust == RustString => {
650                    quote_spanned!(span=> #call.into_string())
651                }
652                Type::RustBox(ty) => {
653                    if types.is_considered_improper_ctype(&ty.inner) {
654                        quote_spanned!(span=> ::cxx::alloc::boxed::Box::from_raw(#call.cast()))
655                    } else {
656                        quote_spanned!(span=> ::cxx::alloc::boxed::Box::from_raw(#call))
657                    }
658                }
659                Type::RustVec(vec) => {
660                    if vec.inner == RustString {
661                        quote_spanned!(span=> #call.into_vec_string())
662                    } else {
663                        quote_spanned!(span=> #call.into_vec())
664                    }
665                }
666                Type::UniquePtr(ty) => {
667                    if types.is_considered_improper_ctype(&ty.inner) {
668                        quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call.cast()))
669                    } else {
670                        quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call))
671                    }
672                }
673                Type::Ref(ty) => match &ty.inner {
674                    Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
675                        false => quote_spanned!(span=> #call.as_string()),
676                        true => quote_spanned!(span=> #call.as_mut_string()),
677                    },
678                    Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
679                        false => quote_spanned!(span=> #call.as_vec_string()),
680                        true => quote_spanned!(span=> #call.as_mut_vec_string()),
681                    },
682                    Type::RustVec(_) => match ty.mutable {
683                        false => quote_spanned!(span=> #call.as_vec()),
684                        true => quote_spanned!(span=> #call.as_mut_vec()),
685                    },
686                    inner if types.is_considered_improper_ctype(inner) => {
687                        let mutability = ty.mutability;
688                        let deref_mut = quote_spanned!(span=> &#mutability *#call.cast());
689                        match ty.pinned {
690                            false => deref_mut,
691                            true => {
692                                quote_spanned!(span=> ::cxx::core::pin::Pin::new_unchecked(#deref_mut))
693                            }
694                        }
695                    }
696                    _ => call,
697                },
698                Type::Ptr(ty) => {
699                    if types.is_considered_improper_ctype(&ty.inner) {
700                        quote_spanned!(span=> #call.cast())
701                    } else {
702                        call
703                    }
704                }
705                Type::Str(_) => quote_spanned!(span=> #call.as_str()),
706                Type::SliceRef(slice) => {
707                    let inner = &slice.inner;
708                    match slice.mutable {
709                        false => quote_spanned!(span=> #call.as_slice::<#inner>()),
710                        true => quote_spanned!(span=> #call.as_mut_slice::<#inner>()),
711                    }
712                }
713                _ => call,
714            },
715        };
716        if efn.throws {
717            expr = quote_spanned!(span=> ::cxx::core::result::Result::Ok(#expr));
718        }
719    };
720    let mut dispatch = quote!(#setup #expr);
721    let visibility = efn.visibility;
722    let unsafety = &efn.sig.unsafety;
723    if unsafety.is_none() {
724        dispatch = quote_spanned!(span=> unsafe { #dispatch });
725    }
726    let fn_token = efn.sig.fn_token;
727    let ident = &efn.name.rust;
728    let generics = &efn.generics;
729    let arg_list = quote_spanned!(efn.sig.paren_token.span=> (#(#all_args,)*));
730    let fn_body = quote_spanned!(span=> {
731        extern "C" {
732            #decl
733        }
734        #trampolines
735        #dispatch
736    });
737    match &efn.receiver {
738        None => {
739            quote! {
740                #doc
741                #attrs
742                #visibility #unsafety #fn_token #ident #generics #arg_list #ret #fn_body
743            }
744        }
745        Some(receiver) => {
746            let elided_generics;
747            let receiver_ident = &receiver.ty.rust;
748            let resolve = types.resolve(&receiver.ty);
749            let receiver_generics = if receiver.ty.generics.lt_token.is_some() {
750                &receiver.ty.generics
751            } else {
752                elided_generics = Lifetimes {
753                    lt_token: resolve.generics.lt_token,
754                    lifetimes: resolve
755                        .generics
756                        .lifetimes
757                        .pairs()
758                        .map(|pair| {
759                            let lifetime = Lifetime::new("'_", pair.value().apostrophe);
760                            let punct = pair.punct().map(|&&comma| comma);
761                            punctuated::Pair::new(lifetime, punct)
762                        })
763                        .collect(),
764                    gt_token: resolve.generics.gt_token,
765                };
766                &elided_generics
767            };
768            quote_spanned! {ident.span()=>
769                impl #generics #receiver_ident #receiver_generics {
770                    #doc
771                    #attrs
772                    #visibility #unsafety #fn_token #ident #arg_list #ret #fn_body
773                }
774            }
775        }
776    }
777}
778
779fn expand_function_pointer_trampoline(
780    efn: &ExternFn,
781    var: &Pair,
782    sig: &Signature,
783    types: &Types,
784) -> TokenStream {
785    let c_trampoline = mangle::c_trampoline(efn, var, types);
786    let r_trampoline = mangle::r_trampoline(efn, var, types);
787    let local_name = parse_quote!(__);
788    let prevent_unwind_label = format!("::{}::{}", efn.name.rust, var.rust);
789    let body_span = efn.semi_token.span;
790    let shim = expand_rust_function_shim_impl(
791        sig,
792        types,
793        &r_trampoline,
794        local_name,
795        prevent_unwind_label,
796        None,
797        Some(&efn.generics),
798        &efn.attrs,
799        body_span,
800    );
801    let var = &var.rust;
802
803    quote! {
804        let #var = ::cxx::private::FatFunction {
805            trampoline: {
806                extern "C" {
807                    #[link_name = #c_trampoline]
808                    fn trampoline();
809                }
810                #shim
811                trampoline as usize as *const ::cxx::core::ffi::c_void
812            },
813            ptr: #var as usize as *const ::cxx::core::ffi::c_void,
814        };
815    }
816}
817
818fn expand_rust_type_import(ety: &ExternType) -> TokenStream {
819    let ident = &ety.name.rust;
820    let span = ident.span();
821
822    quote_spanned! {span=>
823        use super::#ident;
824    }
825}
826
827fn expand_rust_type_impl(ety: &ExternType) -> TokenStream {
828    let ident = &ety.name.rust;
829    let generics = &ety.generics;
830    let span = ident.span();
831    let unsafe_impl = quote_spanned!(ety.type_token.span=> unsafe impl);
832
833    let mut impls = quote_spanned! {span=>
834        #[doc(hidden)]
835        #unsafe_impl #generics ::cxx::private::RustType for #ident #generics {}
836    };
837
838    for derive in &ety.derives {
839        if derive.what == Trait::ExternType {
840            let type_id = type_id(&ety.name);
841            let span = derive.span;
842            impls.extend(quote_spanned! {span=>
843                unsafe impl #generics ::cxx::ExternType for #ident #generics {
844                    #[allow(unused_attributes)] // incorrect lint
845                    #[doc(hidden)]
846                    type Id = #type_id;
847                    type Kind = ::cxx::kind::Opaque;
848                }
849            });
850        }
851    }
852
853    impls
854}
855
856fn expand_rust_type_assert_unpin(ety: &ExternType, types: &Types) -> TokenStream {
857    let ident = &ety.name.rust;
858    let begin_span = Token![::](ety.type_token.span);
859    let unpin = quote_spanned! {ety.semi_token.span=>
860        #begin_span cxx::core::marker::Unpin
861    };
862
863    let resolve = types.resolve(ident);
864    let lifetimes = resolve.generics.to_underscore_lifetimes();
865
866    quote_spanned! {ident.span()=>
867        let _ = {
868            fn __AssertUnpin<T: ?::cxx::core::marker::Sized + #unpin>() {}
869            __AssertUnpin::<#ident #lifetimes>
870        };
871    }
872}
873
874fn expand_rust_type_layout(ety: &ExternType, types: &Types) -> TokenStream {
875    // Rustc will render as follows if not sized:
876    //
877    //     type TheirType;
878    //     -----^^^^^^^^^-
879    //     |    |
880    //     |    doesn't have a size known at compile-time
881    //     required by this bound in `__AssertSized`
882
883    let ident = &ety.name.rust;
884    let begin_span = Token![::](ety.type_token.span);
885    let sized = quote_spanned! {ety.semi_token.span=>
886        #begin_span cxx::core::marker::Sized
887    };
888
889    let link_sizeof = mangle::operator(&ety.name, "sizeof");
890    let link_alignof = mangle::operator(&ety.name, "alignof");
891
892    let local_sizeof = format_ident!("__sizeof_{}", ety.name.rust);
893    let local_alignof = format_ident!("__alignof_{}", ety.name.rust);
894
895    let resolve = types.resolve(ident);
896    let lifetimes = resolve.generics.to_underscore_lifetimes();
897
898    quote_spanned! {ident.span()=>
899        {
900            #[doc(hidden)]
901            fn __AssertSized<T: ?#sized + #sized>() -> ::cxx::core::alloc::Layout {
902                ::cxx::core::alloc::Layout::new::<T>()
903            }
904            #[doc(hidden)]
905            #[export_name = #link_sizeof]
906            extern "C" fn #local_sizeof() -> usize {
907                __AssertSized::<#ident #lifetimes>().size()
908            }
909            #[doc(hidden)]
910            #[export_name = #link_alignof]
911            extern "C" fn #local_alignof() -> usize {
912                __AssertSized::<#ident #lifetimes>().align()
913            }
914        }
915    }
916}
917
918fn expand_forbid(impls: TokenStream) -> TokenStream {
919    quote! {
920        mod forbid {
921            pub trait Drop {}
922            #[allow(drop_bounds)]
923            impl<T: ?::cxx::core::marker::Sized + ::cxx::core::ops::Drop> self::Drop for T {}
924            #impls
925        }
926    }
927}
928
929fn expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
930    let link_name = mangle::extern_fn(efn, types);
931    let local_name = match &efn.receiver {
932        None => format_ident!("__{}", efn.name.rust),
933        Some(receiver) => format_ident!("__{}__{}", receiver.ty.rust, efn.name.rust),
934    };
935    let prevent_unwind_label = match &efn.receiver {
936        None => format!("::{}", efn.name.rust),
937        Some(receiver) => format!("::{}::{}", receiver.ty.rust, efn.name.rust),
938    };
939    let invoke = Some(&efn.name.rust);
940    let body_span = efn.semi_token.span;
941    expand_rust_function_shim_impl(
942        efn,
943        types,
944        &link_name,
945        local_name,
946        prevent_unwind_label,
947        invoke,
948        None,
949        &efn.attrs,
950        body_span,
951    )
952}
953
954fn expand_rust_function_shim_impl(
955    sig: &Signature,
956    types: &Types,
957    link_name: &Symbol,
958    local_name: Ident,
959    prevent_unwind_label: String,
960    invoke: Option<&Ident>,
961    outer_generics: Option<&Generics>,
962    attrs: &OtherAttrs,
963    body_span: Span,
964) -> TokenStream {
965    let generics = outer_generics.unwrap_or(&sig.generics);
966    let receiver_var = sig
967        .receiver
968        .as_ref()
969        .map(|receiver| quote_spanned!(receiver.var.span=> __self));
970    let receiver = sig.receiver.as_ref().map(|receiver| {
971        let colon = receiver.colon_token;
972        let receiver_type = receiver.ty();
973        quote!(#receiver_var #colon #receiver_type)
974    });
975    let args = sig.args.iter().map(|arg| {
976        let var = &arg.name.rust;
977        let colon = arg.colon_token;
978        let ty = expand_extern_type(&arg.ty, types, false);
979        if types.needs_indirect_abi(&arg.ty) {
980            quote!(#var #colon *mut #ty)
981        } else {
982            quote!(#var #colon #ty)
983        }
984    });
985    let all_args = receiver.into_iter().chain(args);
986
987    let arg_vars = sig.args.iter().map(|arg| {
988        let var = &arg.name.rust;
989        let span = var.span();
990        match &arg.ty {
991            Type::Ident(i) if i.rust == RustString => {
992                quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_string()))
993            }
994            Type::RustBox(_) => quote_spanned!(span=> ::cxx::alloc::boxed::Box::from_raw(#var)),
995            Type::RustVec(vec) => {
996                if vec.inner == RustString {
997                    quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_vec_string()))
998                } else {
999                    quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_vec()))
1000                }
1001            }
1002            Type::UniquePtr(_) => quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#var)),
1003            Type::Ref(ty) => match &ty.inner {
1004                Type::Ident(i) if i.rust == RustString => match ty.mutable {
1005                    false => quote_spanned!(span=> #var.as_string()),
1006                    true => quote_spanned!(span=> #var.as_mut_string()),
1007                },
1008                Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
1009                    false => quote_spanned!(span=> #var.as_vec_string()),
1010                    true => quote_spanned!(span=> #var.as_mut_vec_string()),
1011                },
1012                Type::RustVec(_) => match ty.mutable {
1013                    false => quote_spanned!(span=> #var.as_vec()),
1014                    true => quote_spanned!(span=> #var.as_mut_vec()),
1015                },
1016                _ => quote!(#var),
1017            },
1018            Type::Str(_) => quote_spanned!(span=> #var.as_str()),
1019            Type::SliceRef(slice) => {
1020                let inner = &slice.inner;
1021                match slice.mutable {
1022                    false => quote_spanned!(span=> #var.as_slice::<#inner>()),
1023                    true => quote_spanned!(span=> #var.as_mut_slice::<#inner>()),
1024                }
1025            }
1026            ty if types.needs_indirect_abi(ty) => {
1027                quote_spanned!(span=> ::cxx::core::ptr::read(#var))
1028            }
1029            _ => quote!(#var),
1030        }
1031    });
1032    let vars: Vec<_> = receiver_var.into_iter().chain(arg_vars).collect();
1033
1034    let wrap_super = invoke.map(|invoke| expand_rust_function_shim_super(sig, &local_name, invoke));
1035
1036    let mut requires_closure;
1037    let mut call = match invoke {
1038        Some(_) => {
1039            requires_closure = false;
1040            quote!(#local_name)
1041        }
1042        None => {
1043            requires_closure = true;
1044            quote!(::cxx::core::mem::transmute::<*const (), #sig>(__extern))
1045        }
1046    };
1047    requires_closure |= !vars.is_empty();
1048    call.extend(quote! { (#(#vars),*) });
1049
1050    let span = body_span;
1051    let conversion = sig.ret.as_ref().and_then(|ret| match ret {
1052        Type::Ident(ident) if ident.rust == RustString => {
1053            Some(quote_spanned!(span=> ::cxx::private::RustString::from))
1054        }
1055        Type::RustBox(_) => Some(quote_spanned!(span=> ::cxx::alloc::boxed::Box::into_raw)),
1056        Type::RustVec(vec) => {
1057            if vec.inner == RustString {
1058                Some(quote_spanned!(span=> ::cxx::private::RustVec::from_vec_string))
1059            } else {
1060                Some(quote_spanned!(span=> ::cxx::private::RustVec::from))
1061            }
1062        }
1063        Type::UniquePtr(_) => Some(quote_spanned!(span=> ::cxx::UniquePtr::into_raw)),
1064        Type::Ref(ty) => match &ty.inner {
1065            Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
1066                false => Some(quote_spanned!(span=> ::cxx::private::RustString::from_ref)),
1067                true => Some(quote_spanned!(span=> ::cxx::private::RustString::from_mut)),
1068            },
1069            Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
1070                false => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_ref_vec_string)),
1071                true => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_mut_vec_string)),
1072            },
1073            Type::RustVec(_) => match ty.mutable {
1074                false => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_ref)),
1075                true => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_mut)),
1076            },
1077            _ => None,
1078        },
1079        Type::Str(_) => Some(quote_spanned!(span=> ::cxx::private::RustStr::from)),
1080        Type::SliceRef(ty) => match ty.mutable {
1081            false => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_ref)),
1082            true => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_mut)),
1083        },
1084        _ => None,
1085    });
1086
1087    let mut expr = match conversion {
1088        None => call,
1089        Some(conversion) if !sig.throws => {
1090            requires_closure = true;
1091            quote_spanned!(span=> #conversion(#call))
1092        }
1093        Some(conversion) => {
1094            requires_closure = true;
1095            quote_spanned!(span=> ::cxx::core::result::Result::map(#call, #conversion))
1096        }
1097    };
1098
1099    let mut outparam = None;
1100    let indirect_return = indirect_return(sig, types);
1101    if indirect_return {
1102        let ret = expand_extern_type(sig.ret.as_ref().unwrap(), types, false);
1103        outparam = Some(quote_spanned!(span=> __return: *mut #ret,));
1104    }
1105    if sig.throws {
1106        let out = match sig.ret {
1107            Some(_) => quote_spanned!(span=> __return),
1108            None => quote_spanned!(span=> &mut ()),
1109        };
1110        requires_closure = true;
1111        expr = quote_spanned!(span=> ::cxx::private::r#try(#out, #expr));
1112    } else if indirect_return {
1113        requires_closure = true;
1114        expr = quote_spanned!(span=> ::cxx::core::ptr::write(__return, #expr));
1115    }
1116
1117    let closure = if requires_closure {
1118        quote_spanned!(span=> move || #expr)
1119    } else {
1120        quote!(#local_name)
1121    };
1122
1123    expr = quote_spanned!(span=> ::cxx::private::prevent_unwind(__fn, #closure));
1124
1125    let ret = if sig.throws {
1126        quote!(-> ::cxx::private::Result)
1127    } else {
1128        expand_extern_return_type(&sig.ret, types, false)
1129    };
1130
1131    let pointer = match invoke {
1132        None => Some(quote_spanned!(span=> __extern: *const ())),
1133        Some(_) => None,
1134    };
1135
1136    quote_spanned! {span=>
1137        #attrs
1138        #[doc(hidden)]
1139        #[export_name = #link_name]
1140        unsafe extern "C" fn #local_name #generics(#(#all_args,)* #outparam #pointer) #ret {
1141            let __fn = ::cxx::private::concat!(::cxx::private::module_path!(), #prevent_unwind_label);
1142            #wrap_super
1143            #expr
1144        }
1145    }
1146}
1147
1148// A wrapper like `fn f(x: Arg) { super::f(x) }` just to ensure we have the
1149// accurate unsafety declaration and no problematic elided lifetimes.
1150fn expand_rust_function_shim_super(
1151    sig: &Signature,
1152    local_name: &Ident,
1153    invoke: &Ident,
1154) -> TokenStream {
1155    let unsafety = sig.unsafety;
1156    let generics = &sig.generics;
1157
1158    let receiver_var = sig
1159        .receiver
1160        .as_ref()
1161        .map(|receiver| Ident::new("__self", receiver.var.span));
1162    let receiver = sig.receiver.iter().map(|receiver| {
1163        let receiver_type = receiver.ty();
1164        quote!(#receiver_var: #receiver_type)
1165    });
1166    let args = sig.args.iter().map(|arg| quote!(#arg));
1167    let all_args = receiver.chain(args);
1168
1169    let ret = if let Some((result, _langle, rangle)) = sig.throws_tokens {
1170        let ok = match &sig.ret {
1171            Some(ret) => quote!(#ret),
1172            None => quote!(()),
1173        };
1174        // Set spans that result in the `Result<...>` written by the user being
1175        // highlighted as the cause if their error type has no Display impl.
1176        let result_begin = quote_spanned!(result.span=> ::cxx::core::result::Result<#ok, impl);
1177        let result_end = quote_spanned!(rangle.span=> ::cxx::core::fmt::Display>);
1178        quote!(-> #result_begin #result_end)
1179    } else {
1180        expand_return_type(&sig.ret)
1181    };
1182
1183    let arg_vars = sig.args.iter().map(|arg| &arg.name.rust);
1184    let vars = receiver_var.iter().chain(arg_vars);
1185
1186    let span = invoke.span();
1187    let call = match &sig.receiver {
1188        None => quote_spanned!(span=> super::#invoke),
1189        Some(receiver) => {
1190            let receiver_type = &receiver.ty.rust;
1191            quote_spanned!(span=> #receiver_type::#invoke)
1192        }
1193    };
1194
1195    quote_spanned! {span=>
1196        #unsafety fn #local_name #generics(#(#all_args,)*) #ret {
1197            #call(#(#vars,)*)
1198        }
1199    }
1200}
1201
1202fn expand_type_alias(alias: &TypeAlias) -> TokenStream {
1203    let doc = &alias.doc;
1204    let attrs = &alias.attrs;
1205    let visibility = alias.visibility;
1206    let type_token = alias.type_token;
1207    let ident = &alias.name.rust;
1208    let generics = &alias.generics;
1209    let eq_token = alias.eq_token;
1210    let ty = &alias.ty;
1211    let semi_token = alias.semi_token;
1212
1213    quote! {
1214        #doc
1215        #attrs
1216        #visibility #type_token #ident #generics #eq_token #ty #semi_token
1217    }
1218}
1219
1220fn expand_type_alias_verify(alias: &TypeAlias, types: &Types) -> TokenStream {
1221    let ident = &alias.name.rust;
1222    let type_id = type_id(&alias.name);
1223    let begin_span = alias.type_token.span;
1224    let end_span = alias.semi_token.span;
1225    let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type::<);
1226    let end = quote_spanned!(end_span=> >);
1227
1228    let mut verify = quote! {
1229        const _: fn() = #begin #ident, #type_id #end;
1230    };
1231
1232    if types.required_trivial.contains_key(&alias.name.rust) {
1233        let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_kind::<);
1234        verify.extend(quote! {
1235            const _: fn() = #begin #ident, ::cxx::kind::Trivial #end;
1236        });
1237    }
1238
1239    verify
1240}
1241
1242fn type_id(name: &Pair) -> TokenStream {
1243    let namespace_segments = name.namespace.iter();
1244    let mut segments = Vec::with_capacity(namespace_segments.len() + 1);
1245    segments.extend(namespace_segments.cloned());
1246    segments.push(Ident::new(&name.cxx.to_string(), Span::call_site()));
1247    let qualified = QualifiedName { segments };
1248    crate::type_id::expand(Crate::Cxx, qualified)
1249}
1250
1251fn expand_rust_box(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream {
1252    let ident = key.rust;
1253    let resolve = types.resolve(ident);
1254    let link_prefix = format!("cxxbridge1$box${}$", resolve.name.to_symbol());
1255    let link_alloc = format!("{}alloc", link_prefix);
1256    let link_dealloc = format!("{}dealloc", link_prefix);
1257    let link_drop = format!("{}drop", link_prefix);
1258
1259    let local_prefix = format_ident!("{}__box_", ident);
1260    let local_alloc = format_ident!("{}alloc", local_prefix);
1261    let local_dealloc = format_ident!("{}dealloc", local_prefix);
1262    let local_drop = format_ident!("{}drop", local_prefix);
1263
1264    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1265
1266    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1267    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1268    let unsafe_token = format_ident!("unsafe", span = begin_span);
1269    let prevent_unwind_drop_label = format!("::{} as Drop>::drop", ident);
1270
1271    quote_spanned! {end_span=>
1272        #[doc(hidden)]
1273        #unsafe_token impl #impl_generics ::cxx::private::ImplBox for #ident #ty_generics {}
1274        #[doc(hidden)]
1275        #[export_name = #link_alloc]
1276        unsafe extern "C" fn #local_alloc #impl_generics() -> *mut ::cxx::core::mem::MaybeUninit<#ident #ty_generics> {
1277            // No prevent_unwind: the global allocator is not allowed to panic.
1278            //
1279            // TODO: replace with Box::new_uninit when stable.
1280            // https://doc.rust-lang.org/std/boxed/struct.Box.html#method.new_uninit
1281            // https://github.com/rust-lang/rust/issues/63291
1282            ::cxx::alloc::boxed::Box::into_raw(::cxx::alloc::boxed::Box::new(::cxx::core::mem::MaybeUninit::uninit()))
1283        }
1284        #[doc(hidden)]
1285        #[export_name = #link_dealloc]
1286        unsafe extern "C" fn #local_dealloc #impl_generics(ptr: *mut ::cxx::core::mem::MaybeUninit<#ident #ty_generics>) {
1287            // No prevent_unwind: the global allocator is not allowed to panic.
1288            let _ = ::cxx::alloc::boxed::Box::from_raw(ptr);
1289        }
1290        #[doc(hidden)]
1291        #[export_name = #link_drop]
1292        unsafe extern "C" fn #local_drop #impl_generics(this: *mut ::cxx::alloc::boxed::Box<#ident #ty_generics>) {
1293            let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1294            ::cxx::private::prevent_unwind(__fn, || ::cxx::core::ptr::drop_in_place(this));
1295        }
1296    }
1297}
1298
1299fn expand_rust_vec(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream {
1300    let elem = key.rust;
1301    let resolve = types.resolve(elem);
1302    let link_prefix = format!("cxxbridge1$rust_vec${}$", resolve.name.to_symbol());
1303    let link_new = format!("{}new", link_prefix);
1304    let link_drop = format!("{}drop", link_prefix);
1305    let link_len = format!("{}len", link_prefix);
1306    let link_capacity = format!("{}capacity", link_prefix);
1307    let link_data = format!("{}data", link_prefix);
1308    let link_reserve_total = format!("{}reserve_total", link_prefix);
1309    let link_set_len = format!("{}set_len", link_prefix);
1310    let link_truncate = format!("{}truncate", link_prefix);
1311
1312    let local_prefix = format_ident!("{}__vec_", elem);
1313    let local_new = format_ident!("{}new", local_prefix);
1314    let local_drop = format_ident!("{}drop", local_prefix);
1315    let local_len = format_ident!("{}len", local_prefix);
1316    let local_capacity = format_ident!("{}capacity", local_prefix);
1317    let local_data = format_ident!("{}data", local_prefix);
1318    let local_reserve_total = format_ident!("{}reserve_total", local_prefix);
1319    let local_set_len = format_ident!("{}set_len", local_prefix);
1320    let local_truncate = format_ident!("{}truncate", local_prefix);
1321
1322    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1323
1324    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1325    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1326    let unsafe_token = format_ident!("unsafe", span = begin_span);
1327    let prevent_unwind_drop_label = format!("::{} as Drop>::drop", elem);
1328
1329    quote_spanned! {end_span=>
1330        #[doc(hidden)]
1331        #unsafe_token impl #impl_generics ::cxx::private::ImplVec for #elem #ty_generics {}
1332        #[doc(hidden)]
1333        #[export_name = #link_new]
1334        unsafe extern "C" fn #local_new #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>) {
1335            // No prevent_unwind: cannot panic.
1336            ::cxx::core::ptr::write(this, ::cxx::private::RustVec::new());
1337        }
1338        #[doc(hidden)]
1339        #[export_name = #link_drop]
1340        unsafe extern "C" fn #local_drop #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>) {
1341            let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1342            ::cxx::private::prevent_unwind(__fn, || ::cxx::core::ptr::drop_in_place(this));
1343        }
1344        #[doc(hidden)]
1345        #[export_name = #link_len]
1346        unsafe extern "C" fn #local_len #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> usize {
1347            // No prevent_unwind: cannot panic.
1348            (*this).len()
1349        }
1350        #[doc(hidden)]
1351        #[export_name = #link_capacity]
1352        unsafe extern "C" fn #local_capacity #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> usize {
1353            // No prevent_unwind: cannot panic.
1354            (*this).capacity()
1355        }
1356        #[doc(hidden)]
1357        #[export_name = #link_data]
1358        unsafe extern "C" fn #local_data #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> *const #elem #ty_generics {
1359            // No prevent_unwind: cannot panic.
1360            (*this).as_ptr()
1361        }
1362        #[doc(hidden)]
1363        #[export_name = #link_reserve_total]
1364        unsafe extern "C" fn #local_reserve_total #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, new_cap: usize) {
1365            // No prevent_unwind: the global allocator is not allowed to panic.
1366            (*this).reserve_total(new_cap);
1367        }
1368        #[doc(hidden)]
1369        #[export_name = #link_set_len]
1370        unsafe extern "C" fn #local_set_len #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, len: usize) {
1371            // No prevent_unwind: cannot panic.
1372            (*this).set_len(len);
1373        }
1374        #[doc(hidden)]
1375        #[export_name = #link_truncate]
1376        unsafe extern "C" fn #local_truncate #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, len: usize) {
1377            let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1378            ::cxx::private::prevent_unwind(__fn, || (*this).truncate(len));
1379        }
1380    }
1381}
1382
1383fn expand_unique_ptr(
1384    key: NamedImplKey,
1385    types: &Types,
1386    explicit_impl: Option<&Impl>,
1387) -> TokenStream {
1388    let ident = key.rust;
1389    let name = ident.to_string();
1390    let resolve = types.resolve(ident);
1391    let prefix = format!("cxxbridge1$unique_ptr${}$", resolve.name.to_symbol());
1392    let link_null = format!("{}null", prefix);
1393    let link_uninit = format!("{}uninit", prefix);
1394    let link_raw = format!("{}raw", prefix);
1395    let link_get = format!("{}get", prefix);
1396    let link_release = format!("{}release", prefix);
1397    let link_drop = format!("{}drop", prefix);
1398
1399    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1400
1401    let can_construct_from_value = types.is_maybe_trivial(ident);
1402    let new_method = if can_construct_from_value {
1403        Some(quote! {
1404            fn __new(value: Self) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1405                extern "C" {
1406                    #[link_name = #link_uninit]
1407                    fn __uninit(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::core::ffi::c_void;
1408                }
1409                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1410                unsafe { __uninit(&mut repr).cast::<#ident #ty_generics>().write(value) }
1411                repr
1412            }
1413        })
1414    } else {
1415        None
1416    };
1417
1418    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1419    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1420    let unsafe_token = format_ident!("unsafe", span = begin_span);
1421
1422    quote_spanned! {end_span=>
1423        #unsafe_token impl #impl_generics ::cxx::private::UniquePtrTarget for #ident #ty_generics {
1424            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1425                f.write_str(#name)
1426            }
1427            fn __null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1428                extern "C" {
1429                    #[link_name = #link_null]
1430                    fn __null(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1431                }
1432                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1433                unsafe { __null(&mut repr) }
1434                repr
1435            }
1436            #new_method
1437            unsafe fn __raw(raw: *mut Self) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1438                extern "C" {
1439                    #[link_name = #link_raw]
1440                    fn __raw(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>, raw: *mut ::cxx::core::ffi::c_void);
1441                }
1442                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1443                __raw(&mut repr, raw.cast());
1444                repr
1445            }
1446            unsafe fn __get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const Self {
1447                extern "C" {
1448                    #[link_name = #link_get]
1449                    fn __get(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::core::ffi::c_void;
1450                }
1451                __get(&repr).cast()
1452            }
1453            unsafe fn __release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut Self {
1454                extern "C" {
1455                    #[link_name = #link_release]
1456                    fn __release(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::core::ffi::c_void;
1457                }
1458                __release(&mut repr).cast()
1459            }
1460            unsafe fn __drop(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) {
1461                extern "C" {
1462                    #[link_name = #link_drop]
1463                    fn __drop(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1464                }
1465                __drop(&mut repr);
1466            }
1467        }
1468    }
1469}
1470
1471fn expand_shared_ptr(
1472    key: NamedImplKey,
1473    types: &Types,
1474    explicit_impl: Option<&Impl>,
1475) -> TokenStream {
1476    let ident = key.rust;
1477    let name = ident.to_string();
1478    let resolve = types.resolve(ident);
1479    let prefix = format!("cxxbridge1$shared_ptr${}$", resolve.name.to_symbol());
1480    let link_null = format!("{}null", prefix);
1481    let link_uninit = format!("{}uninit", prefix);
1482    let link_clone = format!("{}clone", prefix);
1483    let link_get = format!("{}get", prefix);
1484    let link_drop = format!("{}drop", prefix);
1485
1486    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1487
1488    let can_construct_from_value = types.is_maybe_trivial(ident);
1489    let new_method = if can_construct_from_value {
1490        Some(quote! {
1491            unsafe fn __new(value: Self, new: *mut ::cxx::core::ffi::c_void) {
1492                extern "C" {
1493                    #[link_name = #link_uninit]
1494                    fn __uninit(new: *mut ::cxx::core::ffi::c_void) -> *mut ::cxx::core::ffi::c_void;
1495                }
1496                __uninit(new).cast::<#ident #ty_generics>().write(value);
1497            }
1498        })
1499    } else {
1500        None
1501    };
1502
1503    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1504    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1505    let unsafe_token = format_ident!("unsafe", span = begin_span);
1506
1507    quote_spanned! {end_span=>
1508        #unsafe_token impl #impl_generics ::cxx::private::SharedPtrTarget for #ident #ty_generics {
1509            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1510                f.write_str(#name)
1511            }
1512            unsafe fn __null(new: *mut ::cxx::core::ffi::c_void) {
1513                extern "C" {
1514                    #[link_name = #link_null]
1515                    fn __null(new: *mut ::cxx::core::ffi::c_void);
1516                }
1517                __null(new);
1518            }
1519            #new_method
1520            unsafe fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void) {
1521                extern "C" {
1522                    #[link_name = #link_clone]
1523                    fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void);
1524                }
1525                __clone(this, new);
1526            }
1527            unsafe fn __get(this: *const ::cxx::core::ffi::c_void) -> *const Self {
1528                extern "C" {
1529                    #[link_name = #link_get]
1530                    fn __get(this: *const ::cxx::core::ffi::c_void) -> *const ::cxx::core::ffi::c_void;
1531                }
1532                __get(this).cast()
1533            }
1534            unsafe fn __drop(this: *mut ::cxx::core::ffi::c_void) {
1535                extern "C" {
1536                    #[link_name = #link_drop]
1537                    fn __drop(this: *mut ::cxx::core::ffi::c_void);
1538                }
1539                __drop(this);
1540            }
1541        }
1542    }
1543}
1544
1545fn expand_weak_ptr(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream {
1546    let ident = key.rust;
1547    let name = ident.to_string();
1548    let resolve = types.resolve(ident);
1549    let prefix = format!("cxxbridge1$weak_ptr${}$", resolve.name.to_symbol());
1550    let link_null = format!("{}null", prefix);
1551    let link_clone = format!("{}clone", prefix);
1552    let link_downgrade = format!("{}downgrade", prefix);
1553    let link_upgrade = format!("{}upgrade", prefix);
1554    let link_drop = format!("{}drop", prefix);
1555
1556    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1557
1558    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1559    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1560    let unsafe_token = format_ident!("unsafe", span = begin_span);
1561
1562    quote_spanned! {end_span=>
1563        #unsafe_token impl #impl_generics ::cxx::private::WeakPtrTarget for #ident #ty_generics {
1564            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1565                f.write_str(#name)
1566            }
1567            unsafe fn __null(new: *mut ::cxx::core::ffi::c_void) {
1568                extern "C" {
1569                    #[link_name = #link_null]
1570                    fn __null(new: *mut ::cxx::core::ffi::c_void);
1571                }
1572                __null(new);
1573            }
1574            unsafe fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void) {
1575                extern "C" {
1576                    #[link_name = #link_clone]
1577                    fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void);
1578                }
1579                __clone(this, new);
1580            }
1581            unsafe fn __downgrade(shared: *const ::cxx::core::ffi::c_void, weak: *mut ::cxx::core::ffi::c_void) {
1582                extern "C" {
1583                    #[link_name = #link_downgrade]
1584                    fn __downgrade(shared: *const ::cxx::core::ffi::c_void, weak: *mut ::cxx::core::ffi::c_void);
1585                }
1586                __downgrade(shared, weak);
1587            }
1588            unsafe fn __upgrade(weak: *const ::cxx::core::ffi::c_void, shared: *mut ::cxx::core::ffi::c_void) {
1589                extern "C" {
1590                    #[link_name = #link_upgrade]
1591                    fn __upgrade(weak: *const ::cxx::core::ffi::c_void, shared: *mut ::cxx::core::ffi::c_void);
1592                }
1593                __upgrade(weak, shared);
1594            }
1595            unsafe fn __drop(this: *mut ::cxx::core::ffi::c_void) {
1596                extern "C" {
1597                    #[link_name = #link_drop]
1598                    fn __drop(this: *mut ::cxx::core::ffi::c_void);
1599                }
1600                __drop(this);
1601            }
1602        }
1603    }
1604}
1605
1606fn expand_cxx_vector(
1607    key: NamedImplKey,
1608    explicit_impl: Option<&Impl>,
1609    types: &Types,
1610) -> TokenStream {
1611    let elem = key.rust;
1612    let name = elem.to_string();
1613    let resolve = types.resolve(elem);
1614    let prefix = format!("cxxbridge1$std$vector${}$", resolve.name.to_symbol());
1615    let link_size = format!("{}size", prefix);
1616    let link_get_unchecked = format!("{}get_unchecked", prefix);
1617    let link_push_back = format!("{}push_back", prefix);
1618    let link_pop_back = format!("{}pop_back", prefix);
1619    let unique_ptr_prefix = format!(
1620        "cxxbridge1$unique_ptr$std$vector${}$",
1621        resolve.name.to_symbol(),
1622    );
1623    let link_unique_ptr_null = format!("{}null", unique_ptr_prefix);
1624    let link_unique_ptr_raw = format!("{}raw", unique_ptr_prefix);
1625    let link_unique_ptr_get = format!("{}get", unique_ptr_prefix);
1626    let link_unique_ptr_release = format!("{}release", unique_ptr_prefix);
1627    let link_unique_ptr_drop = format!("{}drop", unique_ptr_prefix);
1628
1629    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1630
1631    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1632    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1633    let unsafe_token = format_ident!("unsafe", span = begin_span);
1634
1635    let can_pass_element_by_value = types.is_maybe_trivial(elem);
1636    let by_value_methods = if can_pass_element_by_value {
1637        Some(quote_spanned! {end_span=>
1638            unsafe fn __push_back(
1639                this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>,
1640                value: &mut ::cxx::core::mem::ManuallyDrop<Self>,
1641            ) {
1642                extern "C" {
1643                    #[link_name = #link_push_back]
1644                    fn __push_back #impl_generics(
1645                        this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
1646                        value: *mut ::cxx::core::ffi::c_void,
1647                    );
1648                }
1649                __push_back(this, value as *mut ::cxx::core::mem::ManuallyDrop<Self> as *mut ::cxx::core::ffi::c_void);
1650            }
1651            unsafe fn __pop_back(
1652                this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>,
1653                out: &mut ::cxx::core::mem::MaybeUninit<Self>,
1654            ) {
1655                extern "C" {
1656                    #[link_name = #link_pop_back]
1657                    fn __pop_back #impl_generics(
1658                        this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
1659                        out: *mut ::cxx::core::ffi::c_void,
1660                    );
1661                }
1662                __pop_back(this, out as *mut ::cxx::core::mem::MaybeUninit<Self> as *mut ::cxx::core::ffi::c_void);
1663            }
1664        })
1665    } else {
1666        None
1667    };
1668
1669    quote_spanned! {end_span=>
1670        #unsafe_token impl #impl_generics ::cxx::private::VectorElement for #elem #ty_generics {
1671            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1672                f.write_str(#name)
1673            }
1674            fn __vector_size(v: &::cxx::CxxVector<Self>) -> usize {
1675                extern "C" {
1676                    #[link_name = #link_size]
1677                    fn __vector_size #impl_generics(_: &::cxx::CxxVector<#elem #ty_generics>) -> usize;
1678                }
1679                unsafe { __vector_size(v) }
1680            }
1681            unsafe fn __get_unchecked(v: *mut ::cxx::CxxVector<Self>, pos: usize) -> *mut Self {
1682                extern "C" {
1683                    #[link_name = #link_get_unchecked]
1684                    fn __get_unchecked #impl_generics(
1685                        v: *mut ::cxx::CxxVector<#elem #ty_generics>,
1686                        pos: usize,
1687                    ) -> *mut ::cxx::core::ffi::c_void;
1688                }
1689                __get_unchecked(v, pos) as *mut Self
1690            }
1691            #by_value_methods
1692            fn __unique_ptr_null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1693                extern "C" {
1694                    #[link_name = #link_unique_ptr_null]
1695                    fn __unique_ptr_null(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1696                }
1697                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1698                unsafe { __unique_ptr_null(&mut repr) }
1699                repr
1700            }
1701            unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<Self>) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1702                extern "C" {
1703                    #[link_name = #link_unique_ptr_raw]
1704                    fn __unique_ptr_raw #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>, raw: *mut ::cxx::CxxVector<#elem #ty_generics>);
1705                }
1706                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1707                __unique_ptr_raw(&mut repr, raw);
1708                repr
1709            }
1710            unsafe fn __unique_ptr_get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<Self> {
1711                extern "C" {
1712                    #[link_name = #link_unique_ptr_get]
1713                    fn __unique_ptr_get #impl_generics(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<#elem #ty_generics>;
1714                }
1715                __unique_ptr_get(&repr)
1716            }
1717            unsafe fn __unique_ptr_release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<Self> {
1718                extern "C" {
1719                    #[link_name = #link_unique_ptr_release]
1720                    fn __unique_ptr_release #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<#elem #ty_generics>;
1721                }
1722                __unique_ptr_release(&mut repr)
1723            }
1724            unsafe fn __unique_ptr_drop(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) {
1725                extern "C" {
1726                    #[link_name = #link_unique_ptr_drop]
1727                    fn __unique_ptr_drop(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1728                }
1729                __unique_ptr_drop(&mut repr);
1730            }
1731        }
1732    }
1733}
1734
1735fn expand_return_type(ret: &Option<Type>) -> TokenStream {
1736    match ret {
1737        Some(ret) => quote!(-> #ret),
1738        None => TokenStream::new(),
1739    }
1740}
1741
1742fn indirect_return(sig: &Signature, types: &Types) -> bool {
1743    sig.ret
1744        .as_ref()
1745        .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret))
1746}
1747
1748fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream {
1749    match ty {
1750        Type::Ident(ident) if ident.rust == RustString => {
1751            let span = ident.rust.span();
1752            quote_spanned!(span=> ::cxx::private::RustString)
1753        }
1754        Type::RustBox(ty) | Type::UniquePtr(ty) => {
1755            let span = ty.name.span();
1756            if proper && types.is_considered_improper_ctype(&ty.inner) {
1757                quote_spanned!(span=> *mut ::cxx::core::ffi::c_void)
1758            } else {
1759                let inner = expand_extern_type(&ty.inner, types, proper);
1760                quote_spanned!(span=> *mut #inner)
1761            }
1762        }
1763        Type::RustVec(ty) => {
1764            let span = ty.name.span();
1765            let langle = ty.langle;
1766            let elem = expand_extern_type(&ty.inner, types, proper);
1767            let rangle = ty.rangle;
1768            quote_spanned!(span=> ::cxx::private::RustVec #langle #elem #rangle)
1769        }
1770        Type::Ref(ty) => {
1771            let ampersand = ty.ampersand;
1772            let lifetime = &ty.lifetime;
1773            let mutability = ty.mutability;
1774            match &ty.inner {
1775                Type::Ident(ident) if ident.rust == RustString => {
1776                    let span = ident.rust.span();
1777                    quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustString)
1778                }
1779                Type::RustVec(ty) => {
1780                    let span = ty.name.span();
1781                    let langle = ty.langle;
1782                    let inner = expand_extern_type(&ty.inner, types, proper);
1783                    let rangle = ty.rangle;
1784                    quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustVec #langle #inner #rangle)
1785                }
1786                inner if proper && types.is_considered_improper_ctype(inner) => {
1787                    let star = Token![*](ampersand.span);
1788                    match ty.mutable {
1789                        false => quote!(#star const ::cxx::core::ffi::c_void),
1790                        true => quote!(#star #mutability ::cxx::core::ffi::c_void),
1791                    }
1792                }
1793                _ => quote!(#ty),
1794            }
1795        }
1796        Type::Ptr(ty) => {
1797            if proper && types.is_considered_improper_ctype(&ty.inner) {
1798                let star = ty.star;
1799                let mutability = ty.mutability;
1800                let constness = ty.constness;
1801                quote!(#star #mutability #constness ::cxx::core::ffi::c_void)
1802            } else {
1803                quote!(#ty)
1804            }
1805        }
1806        Type::Str(ty) => {
1807            let span = ty.ampersand.span;
1808            let rust_str = Ident::new("RustStr", syn::spanned::Spanned::span(&ty.inner));
1809            quote_spanned!(span=> ::cxx::private::#rust_str)
1810        }
1811        Type::SliceRef(ty) => {
1812            let span = ty.ampersand.span;
1813            let rust_slice = Ident::new("RustSlice", ty.bracket.span.join());
1814            quote_spanned!(span=> ::cxx::private::#rust_slice)
1815        }
1816        _ => quote!(#ty),
1817    }
1818}
1819
1820fn expand_extern_return_type(ret: &Option<Type>, types: &Types, proper: bool) -> TokenStream {
1821    let ret = match ret {
1822        Some(ret) if !types.needs_indirect_abi(ret) => ret,
1823        _ => return TokenStream::new(),
1824    };
1825    let ty = expand_extern_type(ret, types, proper);
1826    quote!(-> #ty)
1827}
1828