cxxbridge_macro/
expand.rs

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