cxxbridge_macro/
expand.rs

1use crate::syntax::atom::Atom::*;
2use crate::syntax::attrs::{self, OtherAttrs};
3use crate::syntax::cfg::{CfgExpr, ComputedCfg};
4use crate::syntax::file::Module;
5use crate::syntax::instantiate::{ImplKey, NamedImplKey};
6use crate::syntax::message::Message;
7use crate::syntax::namespace::Namespace;
8use crate::syntax::qualified::QualifiedName;
9use crate::syntax::report::Errors;
10use crate::syntax::symbol::Symbol;
11use crate::syntax::trivial::TrivialReason;
12use crate::syntax::types::ConditionalImpl;
13use crate::syntax::unpin::UnpinReason;
14use crate::syntax::{
15    self, check, mangle, Api, Doc, Enum, ExternFn, ExternType, FnKind, Lang, Lifetimes, Pair,
16    Signature, Struct, Trait, Type, TypeAlias, Types,
17};
18use crate::type_id::Crate;
19use crate::{derive, generics};
20use proc_macro2::{Ident, Span, TokenStream};
21use quote::{format_ident, quote, quote_spanned, ToTokens};
22use std::fmt::{self, Display};
23use std::mem;
24use syn::{parse_quote, punctuated, Generics, Lifetime, Result, Token, Visibility};
25
26pub(crate) fn bridge(mut ffi: Module) -> Result<TokenStream> {
27    let ref mut errors = Errors::new();
28
29    let mut cfg = CfgExpr::Unconditional;
30    let mut doc = Doc::new();
31    let attrs = attrs::parse(
32        errors,
33        mem::take(&mut ffi.attrs),
34        attrs::Parser {
35            cfg: Some(&mut cfg),
36            doc: Some(&mut doc),
37            ..Default::default()
38        },
39    );
40
41    let content = mem::take(&mut ffi.content);
42    let trusted = ffi.unsafety.is_some();
43    let namespace = &ffi.namespace;
44    let ref mut apis = syntax::parse_items(errors, content, trusted, namespace);
45    let ref types = Types::collect(errors, apis);
46    errors.propagate()?;
47
48    let generator = check::Generator::Macro;
49    check::typecheck(errors, apis, types, generator);
50    errors.propagate()?;
51
52    Ok(expand(ffi, doc, attrs, apis, types))
53}
54
55fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types) -> TokenStream {
56    let mut expanded = TokenStream::new();
57    let mut hidden = TokenStream::new();
58    let mut forbid = TokenStream::new();
59
60    for api in apis {
61        if let Api::RustType(ety) = api {
62            expanded.extend(expand_rust_type_import(ety));
63            hidden.extend(expand_rust_type_assert_unpin(ety, types));
64        }
65    }
66
67    for api in apis {
68        match api {
69            Api::Include(_) | Api::Impl(_) => {}
70            Api::Struct(strct) => {
71                expanded.extend(expand_struct(strct));
72                hidden.extend(expand_struct_nonempty(strct));
73                hidden.extend(expand_struct_operators(strct));
74                forbid.extend(expand_struct_forbid_drop(strct));
75            }
76            Api::Enum(enm) => expanded.extend(expand_enum(enm)),
77            Api::CxxType(ety) => {
78                let ident = &ety.name.rust;
79                if types.structs.contains_key(ident) {
80                    hidden.extend(expand_extern_shared_struct(ety, &ffi));
81                } else if !types.enums.contains_key(ident) {
82                    expanded.extend(expand_cxx_type(ety));
83                    hidden.extend(expand_cxx_type_assert_pinned(ety, types));
84                }
85            }
86            Api::CxxFunction(efn) => {
87                expanded.extend(expand_cxx_function_shim(efn, types));
88            }
89            Api::RustType(ety) => {
90                expanded.extend(expand_rust_type_impl(ety));
91                hidden.extend(expand_rust_type_layout(ety, types));
92            }
93            Api::RustFunction(efn) => hidden.extend(expand_rust_function_shim(efn, types)),
94            Api::TypeAlias(alias) => {
95                expanded.extend(expand_type_alias(alias));
96                hidden.extend(expand_type_alias_verify(alias, types));
97            }
98        }
99    }
100
101    for (impl_key, conditional_impl) in &types.impls {
102        match impl_key {
103            ImplKey::RustBox(ident) => {
104                hidden.extend(expand_rust_box(ident, types, conditional_impl));
105            }
106            ImplKey::RustVec(ident) => {
107                hidden.extend(expand_rust_vec(ident, types, conditional_impl));
108            }
109            ImplKey::UniquePtr(ident) => {
110                expanded.extend(expand_unique_ptr(ident, types, conditional_impl));
111            }
112            ImplKey::SharedPtr(ident) => {
113                expanded.extend(expand_shared_ptr(ident, types, conditional_impl));
114            }
115            ImplKey::WeakPtr(ident) => {
116                expanded.extend(expand_weak_ptr(ident, types, conditional_impl));
117            }
118            ImplKey::CxxVector(ident) => {
119                expanded.extend(expand_cxx_vector(ident, conditional_impl, types));
120            }
121        }
122    }
123
124    if !forbid.is_empty() {
125        hidden.extend(expand_forbid(forbid));
126    }
127
128    // Work around https://github.com/rust-lang/rust/issues/67851.
129    if !hidden.is_empty() {
130        expanded.extend(quote! {
131            #[doc(hidden)]
132            const _: () = {
133                #hidden
134            };
135        });
136    }
137
138    let vis = &ffi.vis;
139    let mod_token = &ffi.mod_token;
140    let ident = &ffi.ident;
141    let span = ffi.brace_token.span;
142    let expanded = quote_spanned!(span=> {#expanded});
143
144    quote! {
145        #doc
146        #attrs
147        #[deny(improper_ctypes, improper_ctypes_definitions)]
148        #[allow(clippy::unknown_lints)]
149        #[allow(
150            non_camel_case_types,
151            non_snake_case,
152            clippy::extra_unused_type_parameters,
153            clippy::items_after_statements,
154            clippy::no_effect_underscore_binding,
155            clippy::ptr_as_ptr,
156            clippy::ref_as_ptr,
157            clippy::upper_case_acronyms,
158            clippy::use_self,
159        )]
160        #vis #mod_token #ident #expanded
161    }
162}
163
164fn expand_struct(strct: &Struct) -> TokenStream {
165    let ident = &strct.name.rust;
166    let doc = &strct.doc;
167    let attrs = &strct.attrs;
168    let generics = &strct.generics;
169    let type_id = type_id(&strct.name);
170    let fields = strct.fields.iter().map(|field| {
171        let doc = &field.doc;
172        let attrs = &field.attrs;
173        // This span on the pub makes "private type in public interface" errors
174        // appear in the right place.
175        let vis = field.visibility;
176        quote!(#doc #attrs #vis #field)
177    });
178    let mut derives = None;
179    let derived_traits = derive::expand_struct(strct, &mut derives);
180
181    let span = ident.span();
182    let visibility = strct.visibility;
183    let struct_token = strct.struct_token;
184    let struct_def = quote_spanned! {span=>
185        #visibility #struct_token #ident #generics {
186            #(#fields,)*
187        }
188    };
189
190    let align = strct.align.as_ref().map(|align| quote!(, align(#align)));
191
192    quote! {
193        #doc
194        #derives
195        #attrs
196        #[repr(C #align)]
197        #struct_def
198
199        #attrs
200        #[automatically_derived]
201        unsafe impl #generics ::cxx::ExternType for #ident #generics {
202            #[allow(unused_attributes)] // incorrect lint
203            #[doc(hidden)]
204            type Id = #type_id;
205            type Kind = ::cxx::kind::Trivial;
206        }
207
208        #derived_traits
209    }
210}
211
212fn expand_struct_nonempty(strct: &Struct) -> TokenStream {
213    let has_unconditional_field = strct
214        .fields
215        .iter()
216        .any(|field| matches!(field.cfg, CfgExpr::Unconditional));
217    if has_unconditional_field {
218        return TokenStream::new();
219    }
220
221    let mut fields = strct.fields.iter();
222    let mut cfg = ComputedCfg::from(&fields.next().unwrap().cfg);
223    fields.for_each(|field| cfg.merge_or(&field.cfg));
224
225    if let ComputedCfg::Leaf(CfgExpr::Unconditional) = cfg {
226        // At least one field is unconditional, nothing to check.
227        TokenStream::new()
228    } else {
229        let meta = cfg.as_meta();
230        let msg = "structs without any fields are not supported";
231        let error = syn::Error::new_spanned(strct, msg).into_compile_error();
232        quote! {
233            #[cfg(not(#meta))]
234            #error
235        }
236    }
237}
238
239fn expand_struct_operators(strct: &Struct) -> TokenStream {
240    let ident = &strct.name.rust;
241    let generics = &strct.generics;
242    let attrs = &strct.attrs;
243    let mut operators = TokenStream::new();
244
245    for derive in &strct.derives {
246        let span = derive.span;
247        match derive.what {
248            Trait::PartialEq => {
249                let link_name = mangle::operator(&strct.name, "eq");
250                let local_name = format_ident!("__operator_eq_{}", strct.name.rust);
251                let prevent_unwind_label = format!("::{} as PartialEq>::eq", strct.name.rust);
252                operators.extend(quote_spanned! {span=>
253                    #attrs
254                    #[doc(hidden)]
255                    #[#UnsafeAttr(#ExportNameAttr = #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::Eq) {
263                    let link_name = mangle::operator(&strct.name, "ne");
264                    let local_name = format_ident!("__operator_ne_{}", strct.name.rust);
265                    let prevent_unwind_label = format!("::{} as PartialEq>::ne", strct.name.rust);
266                    operators.extend(quote_spanned! {span=>
267                        #attrs
268                        #[doc(hidden)]
269                        #[#UnsafeAttr(#ExportNameAttr = #link_name)]
270                        extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
271                            let __fn = concat!("<", module_path!(), #prevent_unwind_label);
272                            ::cxx::private::prevent_unwind(__fn, || *lhs != *rhs)
273                        }
274                    });
275                }
276            }
277            Trait::PartialOrd => {
278                let link_name = mangle::operator(&strct.name, "lt");
279                let local_name = format_ident!("__operator_lt_{}", strct.name.rust);
280                let prevent_unwind_label = format!("::{} as PartialOrd>::lt", strct.name.rust);
281                operators.extend(quote_spanned! {span=>
282                    #attrs
283                    #[doc(hidden)]
284                    #[#UnsafeAttr(#ExportNameAttr = #link_name)]
285                    extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
286                        let __fn = concat!("<", module_path!(), #prevent_unwind_label);
287                        ::cxx::private::prevent_unwind(__fn, || *lhs < *rhs)
288                    }
289                });
290
291                let link_name = mangle::operator(&strct.name, "le");
292                let local_name = format_ident!("__operator_le_{}", strct.name.rust);
293                let prevent_unwind_label = format!("::{} as PartialOrd>::le", strct.name.rust);
294                operators.extend(quote_spanned! {span=>
295                    #attrs
296                    #[doc(hidden)]
297                    #[#UnsafeAttr(#ExportNameAttr = #link_name)]
298                    extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
299                        let __fn = concat!("<", module_path!(), #prevent_unwind_label);
300                        ::cxx::private::prevent_unwind(__fn, || *lhs <= *rhs)
301                    }
302                });
303
304                if !derive::contains(&strct.derives, Trait::Ord) {
305                    let link_name = mangle::operator(&strct.name, "gt");
306                    let local_name = format_ident!("__operator_gt_{}", strct.name.rust);
307                    let prevent_unwind_label = format!("::{} as PartialOrd>::gt", strct.name.rust);
308                    operators.extend(quote_spanned! {span=>
309                        #attrs
310                        #[doc(hidden)]
311                        #[#UnsafeAttr(#ExportNameAttr = #link_name)]
312                        extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
313                            let __fn = concat!("<", module_path!(), #prevent_unwind_label);
314                            ::cxx::private::prevent_unwind(__fn, || *lhs > *rhs)
315                        }
316                    });
317
318                    let link_name = mangle::operator(&strct.name, "ge");
319                    let local_name = format_ident!("__operator_ge_{}", strct.name.rust);
320                    let prevent_unwind_label = format!("::{} as PartialOrd>::ge", strct.name.rust);
321                    operators.extend(quote_spanned! {span=>
322                        #attrs
323                        #[doc(hidden)]
324                        #[#UnsafeAttr(#ExportNameAttr = #link_name)]
325                        extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
326                            let __fn = concat!("<", module_path!(), #prevent_unwind_label);
327                            ::cxx::private::prevent_unwind(__fn, || *lhs >= *rhs)
328                        }
329                    });
330                }
331            }
332            Trait::Hash => {
333                let link_name = mangle::operator(&strct.name, "hash");
334                let local_name = format_ident!("__operator_hash_{}", strct.name.rust);
335                let prevent_unwind_label = format!("::{} as Hash>::hash", strct.name.rust);
336                operators.extend(quote_spanned! {span=>
337                    #attrs
338                    #[doc(hidden)]
339                    #[#UnsafeAttr(#ExportNameAttr = #link_name)]
340                    #[allow(clippy::cast_possible_truncation)]
341                    extern "C" fn #local_name #generics(this: &#ident #generics) -> usize {
342                        let __fn = concat!("<", module_path!(), #prevent_unwind_label);
343                        ::cxx::private::prevent_unwind(__fn, || ::cxx::private::hash(this))
344                    }
345                });
346            }
347            _ => {}
348        }
349    }
350
351    operators
352}
353
354fn expand_struct_forbid_drop(strct: &Struct) -> TokenStream {
355    let ident = &strct.name.rust;
356    let generics = &strct.generics;
357    let attrs = &strct.attrs;
358    let span = ident.span();
359    let impl_token = Token![impl](strct.visibility.span);
360
361    quote_spanned! {span=>
362        #attrs
363        #[automatically_derived]
364        #impl_token #generics self::Drop for super::#ident #generics {}
365    }
366}
367
368fn expand_enum(enm: &Enum) -> TokenStream {
369    let ident = &enm.name.rust;
370    let doc = &enm.doc;
371    let attrs = &enm.attrs;
372    let repr = &enm.repr;
373    let type_id = type_id(&enm.name);
374    let variants = enm.variants.iter().map(|variant| {
375        let doc = &variant.doc;
376        let attrs = &variant.attrs;
377        let variant_ident = &variant.name.rust;
378        let discriminant = &variant.discriminant;
379        let span = variant_ident.span();
380        Some(quote_spanned! {span=>
381            #doc
382            #attrs
383            #[allow(dead_code)]
384            pub const #variant_ident: Self = #ident { repr: #discriminant };
385        })
386    });
387    let mut derives = None;
388    let derived_traits = derive::expand_enum(enm, &mut derives);
389
390    let span = ident.span();
391    let visibility = enm.visibility;
392    let struct_token = Token![struct](enm.enum_token.span);
393    let enum_repr = quote! {
394        #[allow(missing_docs)]
395        pub repr: #repr,
396    };
397    let enum_def = quote_spanned! {span=>
398        #visibility #struct_token #ident {
399            #enum_repr
400        }
401    };
402
403    quote! {
404        #doc
405        #derives
406        #attrs
407        #[repr(transparent)]
408        #enum_def
409
410        #attrs
411        #[allow(non_upper_case_globals)]
412        impl #ident {
413            #(#variants)*
414        }
415
416        #attrs
417        #[automatically_derived]
418        unsafe impl ::cxx::ExternType for #ident {
419            #[allow(unused_attributes)] // incorrect lint
420            #[doc(hidden)]
421            type Id = #type_id;
422            type Kind = ::cxx::kind::Trivial;
423        }
424
425        #derived_traits
426    }
427}
428
429fn expand_cxx_type(ety: &ExternType) -> TokenStream {
430    let ident = &ety.name.rust;
431    let doc = &ety.doc;
432    let attrs = &ety.attrs;
433    let generics = &ety.generics;
434    let type_id = type_id(&ety.name);
435
436    let lifetime_fields = ety.generics.lifetimes.iter().map(|lifetime| {
437        let field = format_ident!("_lifetime_{}", lifetime.ident);
438        quote!(#field: ::cxx::core::marker::PhantomData<&#lifetime ()>)
439    });
440    let repr_fields = quote! {
441        _private: ::cxx::private::Opaque,
442        #(#lifetime_fields,)*
443    };
444
445    let span = ident.span();
446    let visibility = &ety.visibility;
447    let struct_token = Token![struct](ety.type_token.span);
448    let extern_type_def = quote_spanned! {span=>
449        #visibility #struct_token #ident #generics {
450            #repr_fields
451        }
452    };
453
454    quote! {
455        #doc
456        #attrs
457        #[repr(C)]
458        #extern_type_def
459
460        #attrs
461        #[automatically_derived]
462        unsafe impl #generics ::cxx::ExternType for #ident #generics {
463            #[allow(unused_attributes)] // incorrect lint
464            #[doc(hidden)]
465            type Id = #type_id;
466            type Kind = ::cxx::kind::Opaque;
467        }
468    }
469}
470
471fn expand_cxx_type_assert_pinned(ety: &ExternType, types: &Types) -> TokenStream {
472    let ident = &ety.name.rust;
473    let attrs = &ety.attrs;
474    let infer = Token![_](ident.span());
475
476    let resolve = types.resolve(ident);
477    let lifetimes = resolve.generics.to_underscore_lifetimes();
478
479    quote! {
480        #attrs
481        let _: fn() = {
482            // Derived from https://github.com/nvzqz/static-assertions-rs.
483            trait __AmbiguousIfImpl<A> {
484                fn infer() {}
485            }
486
487            #[automatically_derived]
488            impl<T> __AmbiguousIfImpl<()> for T
489            where
490                T: ?::cxx::core::marker::Sized
491            {}
492
493            #[allow(dead_code)]
494            struct __Invalid;
495
496            #[automatically_derived]
497            impl<T> __AmbiguousIfImpl<__Invalid> for T
498            where
499                T: ?::cxx::core::marker::Sized + ::cxx::core::marker::Unpin,
500            {}
501
502            // If there is only one specialized trait impl, type inference with
503            // `_` can be resolved and this can compile. Fails to compile if
504            // user has added a manual Unpin impl for their opaque C++ type as
505            // then `__AmbiguousIfImpl<__Invalid>` also exists.
506            <#ident #lifetimes as __AmbiguousIfImpl<#infer>>::infer
507        };
508    }
509}
510
511fn expand_extern_shared_struct(ety: &ExternType, ffi: &Module) -> TokenStream {
512    let module = &ffi.ident;
513    let name = &ety.name.rust;
514    let namespaced_name = display_namespaced(&ety.name);
515    let attrs = &ety.attrs;
516
517    let visibility = match &ffi.vis {
518        Visibility::Public(_) => "pub ".to_owned(),
519        Visibility::Restricted(vis) => {
520            format!(
521                "pub(in {}) ",
522                vis.path
523                    .segments
524                    .iter()
525                    .map(|segment| segment.ident.to_string())
526                    .collect::<Vec<_>>()
527                    .join("::"),
528            )
529        }
530        Visibility::Inherited => String::new(),
531    };
532
533    let namespace_attr = if ety.name.namespace == Namespace::ROOT {
534        String::new()
535    } else {
536        format!(
537            "#[namespace = \"{}\"]\n        ",
538            ety.name
539                .namespace
540                .iter()
541                .map(Ident::to_string)
542                .collect::<Vec<_>>()
543                .join("::"),
544        )
545    };
546
547    let message = format!(
548        "\
549        \nShared struct redeclared as an unsafe extern C++ type is deprecated.\
550        \nIf this is intended to be a shared struct, remove this `type {name}`.\
551        \nIf this is intended to be an extern type, change it to:\
552        \n\
553        \n    use cxx::ExternType;\
554        \n    \
555        \n    #[repr(C)]\
556        \n    {visibility}struct {name} {{\
557        \n        ...\
558        \n    }}\
559        \n    \
560        \n    unsafe impl ExternType for {name} {{\
561        \n        type Id = cxx::type_id!(\"{namespaced_name}\");\
562        \n        type Kind = cxx::kind::Trivial;\
563        \n    }}\
564        \n    \
565        \n    {visibility}mod {module} {{\
566        \n        {namespace_attr}extern \"C++\" {{\
567        \n            type {name} = crate::{name};\
568        \n        }}\
569        \n        ...\
570        \n    }}",
571    );
572
573    quote! {
574        #attrs
575        #[deprecated = #message]
576        struct #name {}
577
578        #attrs
579        let _ = #name {};
580    }
581}
582
583fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream {
584    let generics = &efn.generics;
585    let receiver = efn.receiver().into_iter().map(|receiver| {
586        if types.is_considered_improper_ctype(&receiver.ty) {
587            if receiver.mutable {
588                quote!(_: *mut ::cxx::core::ffi::c_void)
589            } else {
590                quote!(_: *const ::cxx::core::ffi::c_void)
591            }
592        } else {
593            let receiver_type = receiver.ty();
594            quote!(_: #receiver_type)
595        }
596    });
597    let args = efn.args.iter().map(|arg| {
598        let var = &arg.name.rust;
599        let colon = arg.colon_token;
600        let ty = expand_extern_type(&arg.ty, types, true);
601        if arg.ty == RustString {
602            quote!(#var #colon *const #ty)
603        } else if let Type::RustVec(_) = arg.ty {
604            quote!(#var #colon *const #ty)
605        } else if let Type::Fn(_) = arg.ty {
606            quote!(#var #colon ::cxx::private::FatFunction)
607        } else if types.needs_indirect_abi(&arg.ty) {
608            quote!(#var #colon *mut #ty)
609        } else {
610            quote!(#var #colon #ty)
611        }
612    });
613    let all_args = receiver.chain(args);
614    let ret = if efn.throws {
615        quote!(-> ::cxx::private::Result)
616    } else {
617        expand_extern_return_type(efn, types, true, efn.lang)
618    };
619    let mut outparam = None;
620    if indirect_return(efn, types, efn.lang) {
621        let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
622        outparam = Some(quote!(__return: *mut #ret));
623    }
624    let link_name = mangle::extern_fn(efn, types);
625    let local_name = format_ident!("__{}", efn.name.rust);
626    quote! {
627        #[link_name = #link_name]
628        fn #local_name #generics(#(#all_args,)* #outparam) #ret;
629    }
630}
631
632fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
633    let doc = &efn.doc;
634    let attrs = &efn.attrs;
635    let decl = expand_cxx_function_decl(efn, types);
636    let receiver = efn.receiver().into_iter().map(|receiver| {
637        let var = receiver.var;
638        if receiver.pinned {
639            let colon = receiver.colon_token;
640            let ty = receiver.ty_self();
641            quote!(#var #colon #ty)
642        } else {
643            let ampersand = receiver.ampersand;
644            let lifetime = &receiver.lifetime;
645            let mutability = receiver.mutability;
646            quote!(#ampersand #lifetime #mutability #var)
647        }
648    });
649    let args = efn.args.iter().map(|arg| quote!(#arg));
650    let all_args = receiver.chain(args);
651    let ret = if efn.throws {
652        let ok = match &efn.ret {
653            Some(ret) => quote!(#ret),
654            None => quote!(()),
655        };
656        quote!(-> ::cxx::core::result::Result<#ok, ::cxx::Exception>)
657    } else {
658        expand_return_type(&efn.ret)
659    };
660    let indirect_return = indirect_return(efn, types, efn.lang);
661    let receiver_var = efn.receiver().into_iter().map(|receiver| {
662        if types.is_considered_improper_ctype(&receiver.ty) {
663            let var = receiver.var;
664            let ty = &receiver.ty.rust;
665            let resolve = types.resolve(ty);
666            let lifetimes = resolve.generics.to_underscore_lifetimes();
667            if receiver.pinned {
668                quote!(::cxx::core::pin::Pin::into_inner_unchecked(#var) as *mut #ty #lifetimes as *mut ::cxx::core::ffi::c_void)
669            } else if receiver.mutable {
670                quote!(#var as *mut #ty #lifetimes as *mut ::cxx::core::ffi::c_void)
671            } else {
672                quote!(#var as *const #ty #lifetimes as *const ::cxx::core::ffi::c_void)
673            }
674        } else {
675            receiver.var.to_token_stream()
676        }
677    });
678    let arg_vars = efn.args.iter().map(|arg| {
679        let var = &arg.name.rust;
680        let span = var.span();
681        match &arg.ty {
682            Type::Ident(ident) if ident.rust == RustString => {
683                quote_spanned!(span=> #var.as_mut_ptr() as *const ::cxx::private::RustString)
684            }
685            Type::RustBox(ty) => {
686                if types.is_considered_improper_ctype(&ty.inner) {
687                    quote_spanned!(span=> ::cxx::alloc::boxed::Box::into_raw(#var).cast())
688                } else {
689                    quote_spanned!(span=> ::cxx::alloc::boxed::Box::into_raw(#var))
690                }
691            }
692            Type::UniquePtr(ty) => {
693                if types.is_considered_improper_ctype(&ty.inner) {
694                    quote_spanned!(span=> ::cxx::UniquePtr::into_raw(#var).cast())
695                } else {
696                    quote_spanned!(span=> ::cxx::UniquePtr::into_raw(#var))
697                }
698            }
699            Type::RustVec(_) => quote_spanned!(span=> #var.as_mut_ptr() as *const ::cxx::private::RustVec<_>),
700            Type::Ref(ty) => match &ty.inner {
701                Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
702                    false => quote_spanned!(span=> ::cxx::private::RustString::from_ref(#var)),
703                    true => quote_spanned!(span=> ::cxx::private::RustString::from_mut(#var)),
704                },
705                Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
706                    false => quote_spanned!(span=> ::cxx::private::RustVec::from_ref_vec_string(#var)),
707                    true => quote_spanned!(span=> ::cxx::private::RustVec::from_mut_vec_string(#var)),
708                },
709                Type::RustVec(_) => match ty.mutable {
710                    false => quote_spanned!(span=> ::cxx::private::RustVec::from_ref(#var)),
711                    true => quote_spanned!(span=> ::cxx::private::RustVec::from_mut(#var)),
712                },
713                inner if types.is_considered_improper_ctype(inner) => {
714                    let var = match ty.pinned {
715                        false => quote!(#var),
716                        true => quote_spanned!(span=> ::cxx::core::pin::Pin::into_inner_unchecked(#var)),
717                    };
718                    match ty.mutable {
719                        false => {
720                            quote_spanned!(span=> #var as *const #inner as *const ::cxx::core::ffi::c_void)
721                        }
722                        true => quote_spanned!(span=> #var as *mut #inner as *mut ::cxx::core::ffi::c_void),
723                    }
724                }
725                _ => quote!(#var),
726            },
727            Type::Ptr(ty) => {
728                if types.is_considered_improper_ctype(&ty.inner) {
729                    quote_spanned!(span=> #var.cast())
730                } else {
731                    quote!(#var)
732                }
733            }
734            Type::Str(_) => quote_spanned!(span=> ::cxx::private::RustStr::from(#var)),
735            Type::SliceRef(ty) => match ty.mutable {
736                false => quote_spanned!(span=> ::cxx::private::RustSlice::from_ref(#var)),
737                true => quote_spanned!(span=> ::cxx::private::RustSlice::from_mut(#var)),
738            },
739            ty if types.needs_indirect_abi(ty) => quote_spanned!(span=> #var.as_mut_ptr()),
740            _ => quote!(#var),
741        }
742    });
743    let vars = receiver_var.chain(arg_vars);
744    let trampolines = efn
745        .args
746        .iter()
747        .filter_map(|arg| {
748            if let Type::Fn(f) = &arg.ty {
749                let var = &arg.name;
750                Some(expand_function_pointer_trampoline(efn, var, f, types))
751            } else {
752                None
753            }
754        })
755        .collect::<TokenStream>();
756    let mut setup = efn
757        .args
758        .iter()
759        .filter(|arg| types.needs_indirect_abi(&arg.ty))
760        .map(|arg| {
761            let var = &arg.name.rust;
762            let span = var.span();
763            // These are arguments for which C++ has taken ownership of the data
764            // behind the mut reference it received.
765            quote_spanned! {span=>
766                let mut #var = ::cxx::core::mem::MaybeUninit::new(#var);
767            }
768        })
769        .collect::<TokenStream>();
770    let local_name = format_ident!("__{}", efn.name.rust);
771    let span = efn.semi_token.span;
772    let call = if indirect_return {
773        let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
774        setup.extend(quote_spanned! {span=>
775            let mut __return = ::cxx::core::mem::MaybeUninit::<#ret>::uninit();
776        });
777        setup.extend(if efn.throws {
778            quote_spanned! {span=>
779                #local_name(#(#vars,)* __return.as_mut_ptr()).exception()?;
780            }
781        } else {
782            quote_spanned! {span=>
783                #local_name(#(#vars,)* __return.as_mut_ptr());
784            }
785        });
786        quote_spanned!(span=> __return.assume_init())
787    } else if efn.throws {
788        quote_spanned! {span=>
789            #local_name(#(#vars),*).exception()
790        }
791    } else {
792        quote_spanned! {span=>
793            #local_name(#(#vars),*)
794        }
795    };
796    let mut expr;
797    if let Some(ret) = &efn.ret {
798        expr = match ret {
799            Type::Ident(ident) if ident.rust == RustString => {
800                quote_spanned!(span=> #call.into_string())
801            }
802            Type::RustBox(ty) => {
803                if types.is_considered_improper_ctype(&ty.inner) {
804                    quote_spanned!(span=> ::cxx::alloc::boxed::Box::from_raw(#call.cast()))
805                } else {
806                    quote_spanned!(span=> ::cxx::alloc::boxed::Box::from_raw(#call))
807                }
808            }
809            Type::RustVec(vec) => {
810                if vec.inner == RustString {
811                    quote_spanned!(span=> #call.into_vec_string())
812                } else {
813                    quote_spanned!(span=> #call.into_vec())
814                }
815            }
816            Type::UniquePtr(ty) => {
817                if types.is_considered_improper_ctype(&ty.inner) {
818                    quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call.cast()))
819                } else {
820                    quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call))
821                }
822            }
823            Type::Ref(ty) => match &ty.inner {
824                Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
825                    false => quote_spanned!(span=> #call.as_string()),
826                    true => quote_spanned!(span=> #call.as_mut_string()),
827                },
828                Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
829                    false => quote_spanned!(span=> #call.as_vec_string()),
830                    true => quote_spanned!(span=> #call.as_mut_vec_string()),
831                },
832                Type::RustVec(_) => match ty.mutable {
833                    false => quote_spanned!(span=> #call.as_vec()),
834                    true => quote_spanned!(span=> #call.as_mut_vec()),
835                },
836                inner if types.is_considered_improper_ctype(inner) => {
837                    let mutability = ty.mutability;
838                    let deref_mut = quote_spanned!(span=> &#mutability *#call.cast());
839                    match ty.pinned {
840                        false => deref_mut,
841                        true => {
842                            quote_spanned!(span=> ::cxx::core::pin::Pin::new_unchecked(#deref_mut))
843                        }
844                    }
845                }
846                _ => call,
847            },
848            Type::Ptr(ty) => {
849                if types.is_considered_improper_ctype(&ty.inner) {
850                    quote_spanned!(span=> #call.cast())
851                } else {
852                    call
853                }
854            }
855            Type::Str(_) => quote_spanned!(span=> #call.as_str()),
856            Type::SliceRef(slice) => {
857                let inner = &slice.inner;
858                match slice.mutable {
859                    false => quote_spanned!(span=> #call.as_slice::<#inner>()),
860                    true => quote_spanned!(span=> #call.as_mut_slice::<#inner>()),
861                }
862            }
863            _ => call,
864        };
865        if efn.throws {
866            expr = quote_spanned!(span=> ::cxx::core::result::Result::Ok(#expr));
867        }
868    } else if efn.throws {
869        expr = call;
870    } else {
871        expr = quote! { #call; };
872    }
873    let dispatch = quote_spanned!(span=> unsafe { #setup #expr });
874    let visibility = efn.visibility;
875    let unsafety = &efn.unsafety;
876    let fn_token = efn.fn_token;
877    let ident = &efn.name.rust;
878    let generics = &efn.generics;
879    let arg_list = quote_spanned!(efn.paren_token.span=> (#(#all_args,)*));
880    let calling_conv = match efn.lang {
881        Lang::Cxx => quote_spanned!(span=> "C"),
882        Lang::CxxUnwind => quote_spanned!(span=> "C-unwind"),
883        Lang::Rust => unreachable!(),
884    };
885    let fn_body = quote_spanned!(span=> {
886        #UnsafeExtern extern #calling_conv {
887            #decl
888        }
889        #trampolines
890        #dispatch
891    });
892    match efn.self_type() {
893        None => {
894            quote! {
895                #doc
896                #attrs
897                #visibility #unsafety #fn_token #ident #generics #arg_list #ret #fn_body
898            }
899        }
900        Some(self_type) => {
901            let elided_generics;
902            let resolve = types.resolve(self_type);
903            let self_type_attrs = resolve.attrs;
904            let self_type_generics = match &efn.kind {
905                FnKind::Method(receiver) if receiver.ty.generics.lt_token.is_some() => {
906                    &receiver.ty.generics
907                }
908                _ => {
909                    elided_generics = Lifetimes {
910                        lt_token: resolve.generics.lt_token,
911                        lifetimes: resolve
912                            .generics
913                            .lifetimes
914                            .pairs()
915                            .map(|pair| {
916                                let lifetime = Lifetime::new("'_", pair.value().apostrophe);
917                                let punct = pair.punct().map(|&&comma| comma);
918                                punctuated::Pair::new(lifetime, punct)
919                            })
920                            .collect(),
921                        gt_token: resolve.generics.gt_token,
922                    };
923                    &elided_generics
924                }
925            };
926            quote_spanned! {ident.span()=>
927                #self_type_attrs
928                impl #generics #self_type #self_type_generics {
929                    #doc
930                    #attrs
931                    #visibility #unsafety #fn_token #ident #arg_list #ret #fn_body
932                }
933            }
934        }
935    }
936}
937
938fn expand_function_pointer_trampoline(
939    efn: &ExternFn,
940    var: &Pair,
941    sig: &Signature,
942    types: &Types,
943) -> TokenStream {
944    let c_trampoline = mangle::c_trampoline(efn, var, types);
945    let r_trampoline = mangle::r_trampoline(efn, var, types);
946    let local_name = parse_quote!(__);
947    let prevent_unwind_label = format!("::{}::{}", efn.name.rust, var.rust);
948    let body_span = efn.semi_token.span;
949    let shim = expand_rust_function_shim_impl(
950        sig,
951        types,
952        &r_trampoline,
953        local_name,
954        prevent_unwind_label,
955        None,
956        Some(&efn.generics),
957        &efn.attrs,
958        body_span,
959    );
960    let calling_conv = match efn.lang {
961        Lang::Cxx => "C",
962        Lang::CxxUnwind => "C-unwind",
963        Lang::Rust => unreachable!(),
964    };
965    let var = &var.rust;
966
967    quote! {
968        let #var = ::cxx::private::FatFunction {
969            trampoline: {
970                #UnsafeExtern extern #calling_conv {
971                    #[link_name = #c_trampoline]
972                    fn trampoline();
973                }
974                #shim
975                trampoline as usize as *const ::cxx::core::ffi::c_void
976            },
977            ptr: #var as usize as *const ::cxx::core::ffi::c_void,
978        };
979    }
980}
981
982fn expand_rust_type_import(ety: &ExternType) -> TokenStream {
983    let ident = &ety.name.rust;
984    let attrs = &ety.attrs;
985    let span = ident.span();
986
987    quote_spanned! {span=>
988        #attrs
989        use super::#ident;
990    }
991}
992
993fn expand_rust_type_impl(ety: &ExternType) -> TokenStream {
994    let ident = &ety.name.rust;
995    let generics = &ety.generics;
996    let attrs = &ety.attrs;
997    let span = ident.span();
998    let unsafe_impl = quote_spanned!(ety.type_token.span=> unsafe impl);
999
1000    let mut impls = quote_spanned! {span=>
1001        #attrs
1002        #[automatically_derived]
1003        #[doc(hidden)]
1004        #unsafe_impl #generics ::cxx::private::RustType for #ident #generics {}
1005    };
1006
1007    for derive in &ety.derives {
1008        if derive.what == Trait::ExternType {
1009            let type_id = type_id(&ety.name);
1010            let span = derive.span;
1011            impls.extend(quote_spanned! {span=>
1012                #attrs
1013                #[automatically_derived]
1014                unsafe impl #generics ::cxx::ExternType for #ident #generics {
1015                    #[allow(unused_attributes)] // incorrect lint
1016                    #[doc(hidden)]
1017                    type Id = #type_id;
1018                    type Kind = ::cxx::kind::Opaque;
1019                }
1020            });
1021        }
1022    }
1023
1024    impls
1025}
1026
1027fn expand_rust_type_assert_unpin(ety: &ExternType, types: &Types) -> TokenStream {
1028    let ident = &ety.name.rust;
1029    let attrs = &ety.attrs;
1030
1031    let resolve = types.resolve(ident);
1032    let lifetimes = resolve.generics.to_underscore_lifetimes();
1033
1034    quote_spanned! {ident.span()=>
1035        #attrs
1036        const _: fn() = ::cxx::private::require_unpin::<#ident #lifetimes>;
1037    }
1038}
1039
1040fn expand_rust_type_layout(ety: &ExternType, types: &Types) -> TokenStream {
1041    // Rustc will render as follows if not sized:
1042    //
1043    //     type TheirType;
1044    //     -----^^^^^^^^^-
1045    //     |    |
1046    //     |    doesn't have a size known at compile-time
1047    //     required by this bound in `__AssertSized`
1048
1049    let ident = &ety.name.rust;
1050    let attrs = &ety.attrs;
1051    let begin_span = Token![::](ety.type_token.span);
1052    let sized = quote_spanned! {ety.semi_token.span=>
1053        #begin_span cxx::core::marker::Sized
1054    };
1055
1056    let link_sizeof = mangle::operator(&ety.name, "sizeof");
1057    let link_alignof = mangle::operator(&ety.name, "alignof");
1058
1059    let local_sizeof = format_ident!("__sizeof_{}", ety.name.rust);
1060    let local_alignof = format_ident!("__alignof_{}", ety.name.rust);
1061
1062    let resolve = types.resolve(ident);
1063    let lifetimes = resolve.generics.to_underscore_lifetimes();
1064
1065    quote_spanned! {ident.span()=>
1066        #attrs
1067        {
1068            #[doc(hidden)]
1069            #[allow(clippy::needless_maybe_sized)]
1070            fn __AssertSized<T: ?#sized + #sized>() -> ::cxx::core::alloc::Layout {
1071                ::cxx::core::alloc::Layout::new::<T>()
1072            }
1073            #[doc(hidden)]
1074            #[#UnsafeAttr(#ExportNameAttr = #link_sizeof)]
1075            extern "C" fn #local_sizeof() -> usize {
1076                __AssertSized::<#ident #lifetimes>().size()
1077            }
1078            #[doc(hidden)]
1079            #[#UnsafeAttr(#ExportNameAttr = #link_alignof)]
1080            extern "C" fn #local_alignof() -> usize {
1081                __AssertSized::<#ident #lifetimes>().align()
1082            }
1083        }
1084    }
1085}
1086
1087fn expand_forbid(impls: TokenStream) -> TokenStream {
1088    quote! {
1089        mod forbid {
1090            pub trait Drop {}
1091            #[automatically_derived]
1092            #[allow(drop_bounds)]
1093            impl<T: ?::cxx::core::marker::Sized + ::cxx::core::ops::Drop> self::Drop for T {}
1094            #impls
1095        }
1096    }
1097}
1098
1099fn expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
1100    let link_name = mangle::extern_fn(efn, types);
1101    let local_name = match efn.self_type() {
1102        None => format_ident!("__{}", efn.name.rust),
1103        Some(self_type) => format_ident!("__{}__{}", self_type, efn.name.rust),
1104    };
1105    let prevent_unwind_label = match efn.self_type() {
1106        None => format!("::{}", efn.name.rust),
1107        Some(self_type) => format!("::{}::{}", self_type, efn.name.rust),
1108    };
1109    let invoke = Some(&efn.name.rust);
1110    let body_span = efn.semi_token.span;
1111    expand_rust_function_shim_impl(
1112        efn,
1113        types,
1114        &link_name,
1115        local_name,
1116        prevent_unwind_label,
1117        invoke,
1118        None,
1119        &efn.attrs,
1120        body_span,
1121    )
1122}
1123
1124fn expand_rust_function_shim_impl(
1125    sig: &Signature,
1126    types: &Types,
1127    link_name: &Symbol,
1128    local_name: Ident,
1129    prevent_unwind_label: String,
1130    invoke: Option<&Ident>,
1131    outer_generics: Option<&Generics>,
1132    attrs: &OtherAttrs,
1133    body_span: Span,
1134) -> TokenStream {
1135    let generics = outer_generics.unwrap_or(&sig.generics);
1136    let receiver_var = sig
1137        .receiver()
1138        .map(|receiver| quote_spanned!(receiver.var.span=> __self));
1139    let receiver = sig.receiver().map(|receiver| {
1140        let colon = receiver.colon_token;
1141        let receiver_type = receiver.ty();
1142        quote!(#receiver_var #colon #receiver_type)
1143    });
1144    let args = sig.args.iter().map(|arg| {
1145        let var = &arg.name.rust;
1146        let colon = arg.colon_token;
1147        let ty = expand_extern_type(&arg.ty, types, false);
1148        if types.needs_indirect_abi(&arg.ty) {
1149            quote!(#var #colon *mut #ty)
1150        } else {
1151            quote!(#var #colon #ty)
1152        }
1153    });
1154    let all_args = receiver.into_iter().chain(args);
1155
1156    let mut requires_unsafe = false;
1157    let arg_vars = sig.args.iter().map(|arg| {
1158        let var = &arg.name.rust;
1159        let span = var.span();
1160        match &arg.ty {
1161            Type::Ident(i) if i.rust == RustString => {
1162                requires_unsafe = true;
1163                quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_string()))
1164            }
1165            Type::RustBox(_) => {
1166                requires_unsafe = true;
1167                quote_spanned!(span=> ::cxx::alloc::boxed::Box::from_raw(#var))
1168            }
1169            Type::RustVec(vec) => {
1170                requires_unsafe = true;
1171                if vec.inner == RustString {
1172                    quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_vec_string()))
1173                } else {
1174                    quote_spanned!(span=> ::cxx::core::mem::take((*#var).as_mut_vec()))
1175                }
1176            }
1177            Type::UniquePtr(_) => {
1178                requires_unsafe = true;
1179                quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#var))
1180            }
1181            Type::Ref(ty) => match &ty.inner {
1182                Type::Ident(i) if i.rust == RustString => match ty.mutable {
1183                    false => quote_spanned!(span=> #var.as_string()),
1184                    true => quote_spanned!(span=> #var.as_mut_string()),
1185                },
1186                Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
1187                    false => quote_spanned!(span=> #var.as_vec_string()),
1188                    true => quote_spanned!(span=> #var.as_mut_vec_string()),
1189                },
1190                Type::RustVec(_) => match ty.mutable {
1191                    false => quote_spanned!(span=> #var.as_vec()),
1192                    true => quote_spanned!(span=> #var.as_mut_vec()),
1193                },
1194                _ => quote!(#var),
1195            },
1196            Type::Str(_) => {
1197                requires_unsafe = true;
1198                quote_spanned!(span=> #var.as_str())
1199            }
1200            Type::SliceRef(slice) => {
1201                requires_unsafe = true;
1202                let inner = &slice.inner;
1203                match slice.mutable {
1204                    false => quote_spanned!(span=> #var.as_slice::<#inner>()),
1205                    true => quote_spanned!(span=> #var.as_mut_slice::<#inner>()),
1206                }
1207            }
1208            ty if types.needs_indirect_abi(ty) => {
1209                requires_unsafe = true;
1210                quote_spanned!(span=> ::cxx::core::ptr::read(#var))
1211            }
1212            _ => quote!(#var),
1213        }
1214    });
1215    let vars: Vec<_> = receiver_var.into_iter().chain(arg_vars).collect();
1216
1217    let wrap_super = invoke.map(|invoke| expand_rust_function_shim_super(sig, &local_name, invoke));
1218
1219    let mut requires_closure;
1220    let mut call = match invoke {
1221        Some(_) => {
1222            requires_closure = false;
1223            quote!(#local_name)
1224        }
1225        None => {
1226            requires_closure = true;
1227            requires_unsafe = true;
1228            quote!(::cxx::core::mem::transmute::<*const (), #sig>(__extern))
1229        }
1230    };
1231    requires_closure |= !vars.is_empty();
1232    call.extend(quote! { (#(#vars),*) });
1233
1234    let span = body_span;
1235    let conversion = sig.ret.as_ref().and_then(|ret| match ret {
1236        Type::Ident(ident) if ident.rust == RustString => {
1237            Some(quote_spanned!(span=> ::cxx::private::RustString::from))
1238        }
1239        Type::RustBox(_) => Some(quote_spanned!(span=> ::cxx::alloc::boxed::Box::into_raw)),
1240        Type::RustVec(vec) => {
1241            if vec.inner == RustString {
1242                Some(quote_spanned!(span=> ::cxx::private::RustVec::from_vec_string))
1243            } else {
1244                Some(quote_spanned!(span=> ::cxx::private::RustVec::from))
1245            }
1246        }
1247        Type::UniquePtr(_) => Some(quote_spanned!(span=> ::cxx::UniquePtr::into_raw)),
1248        Type::Ref(ty) => match &ty.inner {
1249            Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
1250                false => Some(quote_spanned!(span=> ::cxx::private::RustString::from_ref)),
1251                true => Some(quote_spanned!(span=> ::cxx::private::RustString::from_mut)),
1252            },
1253            Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
1254                false => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_ref_vec_string)),
1255                true => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_mut_vec_string)),
1256            },
1257            Type::RustVec(_) => match ty.mutable {
1258                false => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_ref)),
1259                true => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_mut)),
1260            },
1261            _ => None,
1262        },
1263        Type::Str(_) => Some(quote_spanned!(span=> ::cxx::private::RustStr::from)),
1264        Type::SliceRef(ty) => match ty.mutable {
1265            false => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_ref)),
1266            true => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_mut)),
1267        },
1268        _ => None,
1269    });
1270
1271    let mut expr = match conversion {
1272        None => call,
1273        Some(conversion) if !sig.throws => {
1274            requires_closure = true;
1275            quote_spanned!(span=> #conversion(#call))
1276        }
1277        Some(conversion) => {
1278            requires_closure = true;
1279            quote_spanned!(span=> ::cxx::core::result::Result::map(#call, #conversion))
1280        }
1281    };
1282
1283    let mut outparam = None;
1284    let indirect_return = indirect_return(sig, types, Lang::Rust);
1285    if indirect_return {
1286        let ret = expand_extern_type(sig.ret.as_ref().unwrap(), types, false);
1287        outparam = Some(quote_spanned!(span=> __return: *mut #ret,));
1288    }
1289    if sig.throws {
1290        let out = match sig.ret {
1291            Some(_) => quote_spanned!(span=> __return),
1292            None => quote_spanned!(span=> &mut ()),
1293        };
1294        requires_closure = true;
1295        requires_unsafe = true;
1296        expr = quote_spanned!(span=> ::cxx::private::r#try(#out, #expr));
1297    } else if indirect_return {
1298        requires_closure = true;
1299        requires_unsafe = true;
1300        expr = quote_spanned!(span=> ::cxx::core::ptr::write(__return, #expr));
1301    }
1302
1303    if requires_unsafe {
1304        expr = quote_spanned!(span=> unsafe { #expr });
1305    }
1306
1307    let closure = if requires_closure {
1308        quote_spanned!(span=> move || #expr)
1309    } else {
1310        quote!(#local_name)
1311    };
1312
1313    expr = quote_spanned!(span=> ::cxx::private::prevent_unwind(__fn, #closure));
1314
1315    let ret = if sig.throws {
1316        quote!(-> ::cxx::private::Result)
1317    } else {
1318        expand_extern_return_type(sig, types, false, Lang::Rust)
1319    };
1320
1321    let pointer = match invoke {
1322        None => Some(quote_spanned!(span=> __extern: *const ())),
1323        Some(_) => None,
1324    };
1325
1326    quote_spanned! {span=>
1327        #attrs
1328        #[doc(hidden)]
1329        #[#UnsafeAttr(#ExportNameAttr = #link_name)]
1330        unsafe extern "C" fn #local_name #generics(#(#all_args,)* #outparam #pointer) #ret {
1331            let __fn = ::cxx::private::concat!(::cxx::private::module_path!(), #prevent_unwind_label);
1332            #wrap_super
1333            #expr
1334        }
1335    }
1336}
1337
1338// A wrapper like `fn f(x: Arg) { super::f(x) }` just to ensure we have the
1339// accurate unsafety declaration and no problematic elided lifetimes.
1340fn expand_rust_function_shim_super(
1341    sig: &Signature,
1342    local_name: &Ident,
1343    invoke: &Ident,
1344) -> TokenStream {
1345    let unsafety = sig.unsafety;
1346    let generics = &sig.generics;
1347
1348    let receiver_var = sig
1349        .receiver()
1350        .map(|receiver| Ident::new("__self", receiver.var.span));
1351    let receiver = sig.receiver().into_iter().map(|receiver| {
1352        let receiver_type = receiver.ty();
1353        quote!(#receiver_var: #receiver_type)
1354    });
1355    let args = sig.args.iter().map(|arg| quote!(#arg));
1356    let all_args = receiver.chain(args);
1357
1358    let ret = if let Some((result, _langle, rangle)) = sig.throws_tokens {
1359        let ok = match &sig.ret {
1360            Some(ret) => quote!(#ret),
1361            None => quote!(()),
1362        };
1363        // Set spans that result in the `Result<...>` written by the user being
1364        // highlighted as the cause if their error type has no Display impl.
1365        let result_begin = quote_spanned!(result.span=> ::cxx::core::result::Result<#ok, impl);
1366        let result_end = if rustversion::cfg!(since(1.82)) {
1367            // https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html#precise-capturing-use-syntax
1368            quote_spanned!(rangle.span=> ::cxx::core::fmt::Display + use<>>)
1369        } else {
1370            quote_spanned!(rangle.span=> ::cxx::core::fmt::Display>)
1371        };
1372        quote!(-> #result_begin #result_end)
1373    } else {
1374        expand_return_type(&sig.ret)
1375    };
1376
1377    let arg_vars = sig.args.iter().map(|arg| &arg.name.rust);
1378    let vars = receiver_var.iter().chain(arg_vars);
1379
1380    let span = invoke.span();
1381    let call = match sig.self_type() {
1382        None => quote_spanned!(span=> super::#invoke),
1383        Some(self_type) => quote_spanned!(span=> #self_type::#invoke),
1384    };
1385
1386    let mut body = quote_spanned!(span=> #call(#(#vars,)*));
1387    let mut allow_unused_unsafe = None;
1388    if unsafety.is_some() {
1389        body = quote_spanned!(span=> unsafe { #body });
1390        allow_unused_unsafe = Some(quote_spanned!(span=> #[allow(unused_unsafe)]));
1391    }
1392
1393    quote_spanned! {span=>
1394        #allow_unused_unsafe
1395        #unsafety fn #local_name #generics(#(#all_args,)*) #ret {
1396            #body
1397        }
1398    }
1399}
1400
1401fn expand_type_alias(alias: &TypeAlias) -> TokenStream {
1402    let doc = &alias.doc;
1403    let attrs = &alias.attrs;
1404    let visibility = alias.visibility;
1405    let type_token = alias.type_token;
1406    let ident = &alias.name.rust;
1407    let generics = &alias.generics;
1408    let eq_token = alias.eq_token;
1409    let ty = &alias.ty;
1410    let semi_token = alias.semi_token;
1411
1412    quote! {
1413        #doc
1414        #attrs
1415        #visibility #type_token #ident #generics #eq_token #ty #semi_token
1416    }
1417}
1418
1419fn expand_type_alias_verify(alias: &TypeAlias, types: &Types) -> TokenStream {
1420    let attrs = &alias.attrs;
1421    let ident = &alias.name.rust;
1422    let type_id = type_id(&alias.name);
1423    let begin_span = alias.type_token.span;
1424    let end_span = alias.semi_token.span;
1425    let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type::<);
1426    let end = quote_spanned!(end_span=> >);
1427
1428    let resolve = types.resolve(ident);
1429    let lifetimes = resolve.generics.to_underscore_lifetimes();
1430
1431    let mut verify = quote! {
1432        #attrs
1433        const _: fn() = #begin #ident #lifetimes, #type_id #end;
1434    };
1435
1436    let mut require_unpin = false;
1437    let mut require_box = false;
1438    let mut require_vec = false;
1439    let mut require_extern_type_trivial = false;
1440    let mut require_rust_type_or_trivial = None;
1441    if let Some(reasons) = types.required_trivial.get(&alias.name.rust) {
1442        for reason in reasons {
1443            match reason {
1444                TrivialReason::BoxTarget { local: true }
1445                | TrivialReason::VecElement { local: true } => require_unpin = true,
1446                TrivialReason::BoxTarget { local: false } => require_box = true,
1447                TrivialReason::VecElement { local: false } => require_vec = true,
1448                TrivialReason::StructField(_)
1449                | TrivialReason::FunctionArgument(_)
1450                | TrivialReason::FunctionReturn(_) => require_extern_type_trivial = true,
1451                TrivialReason::SliceElement(slice) => require_rust_type_or_trivial = Some(slice),
1452            }
1453        }
1454    }
1455
1456    'unpin: {
1457        if let Some(reason) = types.required_unpin.get(ident) {
1458            let ampersand;
1459            let reference_lifetime;
1460            let mutability;
1461            let mut inner;
1462            let generics;
1463            let shorthand;
1464            match reason {
1465                UnpinReason::Receiver(receiver) => {
1466                    ampersand = &receiver.ampersand;
1467                    reference_lifetime = &receiver.lifetime;
1468                    mutability = &receiver.mutability;
1469                    inner = receiver.ty.rust.clone();
1470                    generics = &receiver.ty.generics;
1471                    shorthand = receiver.shorthand;
1472                    if receiver.shorthand {
1473                        inner.set_span(receiver.var.span);
1474                    }
1475                }
1476                UnpinReason::Ref(mutable_reference) => {
1477                    ampersand = &mutable_reference.ampersand;
1478                    reference_lifetime = &mutable_reference.lifetime;
1479                    mutability = &mutable_reference.mutability;
1480                    let Type::Ident(inner_type) = &mutable_reference.inner else {
1481                        unreachable!();
1482                    };
1483                    inner = inner_type.rust.clone();
1484                    generics = &inner_type.generics;
1485                    shorthand = false;
1486                }
1487                UnpinReason::Slice(mutable_slice) => {
1488                    ampersand = &mutable_slice.ampersand;
1489                    mutability = &mutable_slice.mutability;
1490                    let inner = quote_spanned!(mutable_slice.bracket.span=> [#ident #lifetimes]);
1491                    let trait_name = format_ident!("SliceOfUnpin_{ident}");
1492                    let label = format!("requires `{ident}: Unpin`");
1493                    verify.extend(quote! {
1494                        #attrs
1495                        let _ = {
1496                            #[diagnostic::on_unimplemented(
1497                                message = "mutable slice of pinned type is not supported",
1498                                label = #label,
1499                            )]
1500                            trait #trait_name {
1501                                fn check_unpin() {}
1502                            }
1503                            #[diagnostic::do_not_recommend]
1504                            impl<'a, T: ?::cxx::core::marker::Sized + ::cxx::core::marker::Unpin> #trait_name for &'a #mutability T {}
1505                            <#ampersand #mutability #inner as #trait_name>::check_unpin
1506                        };
1507                    });
1508                    require_unpin = false;
1509                    break 'unpin;
1510                }
1511            }
1512            let trait_name = format_ident!("ReferenceToUnpin_{ident}");
1513            let message =
1514                format!("mutable reference to C++ type requires a pin -- use Pin<&mut {ident}>");
1515            let label = {
1516                let mut label = Message::new();
1517                write!(label, "use `");
1518                if shorthand {
1519                    write!(label, "self: ");
1520                }
1521                write!(label, "Pin<&");
1522                if let Some(reference_lifetime) = reference_lifetime {
1523                    write!(label, "{reference_lifetime} ");
1524                }
1525                write!(label, "mut {ident}");
1526                if !generics.lifetimes.is_empty() {
1527                    write!(label, "<");
1528                    for (i, lifetime) in generics.lifetimes.iter().enumerate() {
1529                        if i > 0 {
1530                            write!(label, ", ");
1531                        }
1532                        write!(label, "{lifetime}");
1533                    }
1534                    write!(label, ">");
1535                } else if shorthand && !alias.generics.lifetimes.is_empty() {
1536                    write!(label, "<");
1537                    for i in 0..alias.generics.lifetimes.len() {
1538                        if i > 0 {
1539                            write!(label, ", ");
1540                        }
1541                        write!(label, "'_");
1542                    }
1543                    write!(label, ">");
1544                }
1545                write!(label, ">`");
1546                label
1547            };
1548            let lifetimes = generics.to_underscore_lifetimes();
1549            verify.extend(quote! {
1550                #attrs
1551                let _ = {
1552                    #[diagnostic::on_unimplemented(message = #message, label = #label)]
1553                    trait #trait_name {
1554                        fn check_unpin() {}
1555                    }
1556                    #[diagnostic::do_not_recommend]
1557                    impl<'a, T: ?::cxx::core::marker::Sized + ::cxx::core::marker::Unpin> #trait_name for &'a mut T {}
1558                    <#ampersand #mutability #inner #lifetimes as #trait_name>::check_unpin
1559                };
1560            });
1561            require_unpin = false;
1562        }
1563    }
1564
1565    if require_unpin {
1566        verify.extend(quote! {
1567            #attrs
1568            const _: fn() = ::cxx::private::require_unpin::<#ident #lifetimes>;
1569        });
1570    }
1571
1572    if require_box {
1573        verify.extend(quote! {
1574            #attrs
1575            const _: fn() = ::cxx::private::require_box::<#ident #lifetimes>;
1576        });
1577    }
1578
1579    if require_vec {
1580        verify.extend(quote! {
1581            #attrs
1582            const _: fn() = ::cxx::private::require_vec::<#ident #lifetimes>;
1583        });
1584    }
1585
1586    if require_extern_type_trivial {
1587        let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_kind::<);
1588        verify.extend(quote! {
1589            #attrs
1590            const _: fn() = #begin #ident #lifetimes, ::cxx::kind::Trivial #end;
1591        });
1592    } else if let Some(slice_type) = require_rust_type_or_trivial {
1593        let ampersand = &slice_type.ampersand;
1594        let mutability = &slice_type.mutability;
1595        let inner = quote_spanned!(slice_type.bracket.span.join()=> [#ident #lifetimes]);
1596        verify.extend(quote! {
1597            #attrs
1598            let _ = || ::cxx::private::with::<#ident #lifetimes>().check_slice::<#ampersand #mutability #inner>();
1599        });
1600    }
1601
1602    verify
1603}
1604
1605fn type_id(name: &Pair) -> TokenStream {
1606    let namespace_segments = name.namespace.iter();
1607    let mut segments = Vec::with_capacity(namespace_segments.len() + 1);
1608    segments.extend(namespace_segments.cloned());
1609    segments.push(Ident::new(&name.cxx.to_string(), Span::call_site()));
1610    let qualified = QualifiedName { segments };
1611    crate::type_id::expand(Crate::Cxx, qualified)
1612}
1613
1614fn expand_rust_box(
1615    key: &NamedImplKey,
1616    types: &Types,
1617    conditional_impl: &ConditionalImpl,
1618) -> TokenStream {
1619    let ident = key.rust;
1620    let resolve = types.resolve(ident);
1621    let link_prefix = format!("cxxbridge1$box${}$", resolve.name.to_symbol());
1622    let link_alloc = format!("{}alloc", link_prefix);
1623    let link_dealloc = format!("{}dealloc", link_prefix);
1624    let link_drop = format!("{}drop", link_prefix);
1625
1626    let local_prefix = format_ident!("{}__box_", ident);
1627    let local_alloc = format_ident!("{}alloc", local_prefix);
1628    let local_dealloc = format_ident!("{}dealloc", local_prefix);
1629    let local_drop = format_ident!("{}drop", local_prefix);
1630
1631    let (impl_generics, ty_generics) = generics::split_for_impl(key, conditional_impl, resolve);
1632
1633    let cfg = conditional_impl.cfg.into_attr();
1634    let begin_span = conditional_impl
1635        .explicit_impl
1636        .map_or(key.begin_span, |explicit| explicit.impl_token.span);
1637    let end_span = conditional_impl
1638        .explicit_impl
1639        .map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1640    let unsafe_token = format_ident!("unsafe", span = begin_span);
1641    let prevent_unwind_drop_label = format!("::{} as Drop>::drop", ident);
1642
1643    quote_spanned! {end_span=>
1644        #cfg
1645        #[automatically_derived]
1646        #[doc(hidden)]
1647        #unsafe_token impl #impl_generics ::cxx::private::ImplBox for #ident #ty_generics {}
1648
1649        #cfg
1650        #[doc(hidden)]
1651        #[#UnsafeAttr(#ExportNameAttr = #link_alloc)]
1652        unsafe extern "C" fn #local_alloc #impl_generics() -> *mut ::cxx::core::mem::MaybeUninit<#ident #ty_generics> {
1653            // No prevent_unwind: the global allocator is not allowed to panic.
1654            //
1655            // TODO: replace with Box::new_uninit when stable.
1656            // https://doc.rust-lang.org/std/boxed/struct.Box.html#method.new_uninit
1657            // https://github.com/rust-lang/rust/issues/63291
1658            ::cxx::alloc::boxed::Box::into_raw(::cxx::alloc::boxed::Box::new(::cxx::core::mem::MaybeUninit::uninit()))
1659        }
1660
1661        #cfg
1662        #[doc(hidden)]
1663        #[#UnsafeAttr(#ExportNameAttr = #link_dealloc)]
1664        unsafe extern "C" fn #local_dealloc #impl_generics(ptr: *mut ::cxx::core::mem::MaybeUninit<#ident #ty_generics>) {
1665            // No prevent_unwind: the global allocator is not allowed to panic.
1666            let _ = unsafe { ::cxx::alloc::boxed::Box::from_raw(ptr) };
1667        }
1668
1669        #cfg
1670        #[doc(hidden)]
1671        #[#UnsafeAttr(#ExportNameAttr = #link_drop)]
1672        unsafe extern "C" fn #local_drop #impl_generics(this: *mut ::cxx::alloc::boxed::Box<#ident #ty_generics>) {
1673            let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1674            ::cxx::private::prevent_unwind(__fn, || unsafe { ::cxx::core::ptr::drop_in_place(this) });
1675        }
1676    }
1677}
1678
1679fn expand_rust_vec(
1680    key: &NamedImplKey,
1681    types: &Types,
1682    conditional_impl: &ConditionalImpl,
1683) -> TokenStream {
1684    let elem = key.rust;
1685    let resolve = types.resolve(elem);
1686    let link_prefix = format!("cxxbridge1$rust_vec${}$", resolve.name.to_symbol());
1687    let link_new = format!("{}new", link_prefix);
1688    let link_drop = format!("{}drop", link_prefix);
1689    let link_len = format!("{}len", link_prefix);
1690    let link_capacity = format!("{}capacity", link_prefix);
1691    let link_data = format!("{}data", link_prefix);
1692    let link_reserve_total = format!("{}reserve_total", link_prefix);
1693    let link_set_len = format!("{}set_len", link_prefix);
1694    let link_truncate = format!("{}truncate", link_prefix);
1695
1696    let local_prefix = format_ident!("{}__vec_", elem);
1697    let local_new = format_ident!("{}new", local_prefix);
1698    let local_drop = format_ident!("{}drop", local_prefix);
1699    let local_len = format_ident!("{}len", local_prefix);
1700    let local_capacity = format_ident!("{}capacity", local_prefix);
1701    let local_data = format_ident!("{}data", local_prefix);
1702    let local_reserve_total = format_ident!("{}reserve_total", local_prefix);
1703    let local_set_len = format_ident!("{}set_len", local_prefix);
1704    let local_truncate = format_ident!("{}truncate", local_prefix);
1705
1706    let (impl_generics, ty_generics) = generics::split_for_impl(key, conditional_impl, resolve);
1707
1708    let cfg = conditional_impl.cfg.into_attr();
1709    let begin_span = conditional_impl
1710        .explicit_impl
1711        .map_or(key.begin_span, |explicit| explicit.impl_token.span);
1712    let end_span = conditional_impl
1713        .explicit_impl
1714        .map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1715    let unsafe_token = format_ident!("unsafe", span = begin_span);
1716    let prevent_unwind_drop_label = format!("::{} as Drop>::drop", elem);
1717
1718    quote_spanned! {end_span=>
1719        #cfg
1720        #[automatically_derived]
1721        #[doc(hidden)]
1722        #unsafe_token impl #impl_generics ::cxx::private::ImplVec for #elem #ty_generics {}
1723
1724        #cfg
1725        #[doc(hidden)]
1726        #[#UnsafeAttr(#ExportNameAttr = #link_new)]
1727        unsafe extern "C" fn #local_new #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>) {
1728            // No prevent_unwind: cannot panic.
1729            unsafe {
1730                ::cxx::core::ptr::write(this, ::cxx::private::RustVec::new());
1731            }
1732        }
1733
1734        #cfg
1735        #[doc(hidden)]
1736        #[#UnsafeAttr(#ExportNameAttr = #link_drop)]
1737        unsafe extern "C" fn #local_drop #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>) {
1738            let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1739            ::cxx::private::prevent_unwind(
1740                __fn,
1741                || unsafe { ::cxx::core::ptr::drop_in_place(this) },
1742            );
1743        }
1744
1745        #cfg
1746        #[doc(hidden)]
1747        #[#UnsafeAttr(#ExportNameAttr = #link_len)]
1748        unsafe extern "C" fn #local_len #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> usize {
1749            // No prevent_unwind: cannot panic.
1750            unsafe { (*this).len() }
1751        }
1752
1753        #cfg
1754        #[doc(hidden)]
1755        #[#UnsafeAttr(#ExportNameAttr = #link_capacity)]
1756        unsafe extern "C" fn #local_capacity #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> usize {
1757            // No prevent_unwind: cannot panic.
1758            unsafe { (*this).capacity() }
1759        }
1760
1761        #cfg
1762        #[doc(hidden)]
1763        #[#UnsafeAttr(#ExportNameAttr = #link_data)]
1764        unsafe extern "C" fn #local_data #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> *const #elem #ty_generics {
1765            // No prevent_unwind: cannot panic.
1766            unsafe { (*this).as_ptr() }
1767        }
1768
1769        #cfg
1770        #[doc(hidden)]
1771        #[#UnsafeAttr(#ExportNameAttr = #link_reserve_total)]
1772        unsafe extern "C" fn #local_reserve_total #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, new_cap: usize) {
1773            // No prevent_unwind: the global allocator is not allowed to panic.
1774            unsafe {
1775                (*this).reserve_total(new_cap);
1776            }
1777        }
1778
1779        #cfg
1780        #[doc(hidden)]
1781        #[#UnsafeAttr(#ExportNameAttr = #link_set_len)]
1782        unsafe extern "C" fn #local_set_len #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, len: usize) {
1783            // No prevent_unwind: cannot panic.
1784            unsafe {
1785                (*this).set_len(len);
1786            }
1787        }
1788
1789        #cfg
1790        #[doc(hidden)]
1791        #[#UnsafeAttr(#ExportNameAttr = #link_truncate)]
1792        unsafe extern "C" fn #local_truncate #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, len: usize) {
1793            let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1794            ::cxx::private::prevent_unwind(
1795                __fn,
1796                || unsafe { (*this).truncate(len) },
1797            );
1798        }
1799    }
1800}
1801
1802fn expand_unique_ptr(
1803    key: &NamedImplKey,
1804    types: &Types,
1805    conditional_impl: &ConditionalImpl,
1806) -> TokenStream {
1807    let ident = key.rust;
1808    let name = ident.to_string();
1809    let resolve = types.resolve(ident);
1810    let prefix = format!("cxxbridge1$unique_ptr${}$", resolve.name.to_symbol());
1811    let link_null = format!("{}null", prefix);
1812    let link_uninit = format!("{}uninit", prefix);
1813    let link_raw = format!("{}raw", prefix);
1814    let link_get = format!("{}get", prefix);
1815    let link_release = format!("{}release", prefix);
1816    let link_drop = format!("{}drop", prefix);
1817
1818    let (impl_generics, ty_generics) = generics::split_for_impl(key, conditional_impl, resolve);
1819
1820    let can_construct_from_value = types.is_maybe_trivial(ident);
1821    let new_method = if can_construct_from_value {
1822        let raw_mut = if rustversion::cfg!(since(1.82)) {
1823            quote!(&raw mut)
1824        } else {
1825            quote!(&mut)
1826        };
1827        Some(quote! {
1828            fn __new(value: Self) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1829                #UnsafeExtern extern "C" {
1830                    #[link_name = #link_uninit]
1831                    fn __uninit(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::core::ffi::c_void;
1832                }
1833                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1834                unsafe {
1835                    __uninit(#raw_mut repr).cast::<#ident #ty_generics>().write(value);
1836                }
1837                repr
1838            }
1839        })
1840    } else {
1841        None
1842    };
1843
1844    let cfg = conditional_impl.cfg.into_attr();
1845    let begin_span = conditional_impl
1846        .explicit_impl
1847        .map_or(key.begin_span, |explicit| explicit.impl_token.span);
1848    let end_span = conditional_impl
1849        .explicit_impl
1850        .map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1851    let unsafe_token = format_ident!("unsafe", span = begin_span);
1852    let raw_const = if rustversion::cfg!(since(1.82)) {
1853        quote_spanned!(end_span=> &raw const)
1854    } else {
1855        quote_spanned!(end_span=> &)
1856    };
1857    let raw_mut = if rustversion::cfg!(since(1.82)) {
1858        quote_spanned!(end_span=> &raw mut)
1859    } else {
1860        quote_spanned!(end_span=> &mut)
1861    };
1862
1863    quote_spanned! {end_span=>
1864        #cfg
1865        #[automatically_derived]
1866        #unsafe_token impl #impl_generics ::cxx::memory::UniquePtrTarget for #ident #ty_generics {
1867            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1868                f.write_str(#name)
1869            }
1870            fn __null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1871                #UnsafeExtern extern "C" {
1872                    #[link_name = #link_null]
1873                    fn __null(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1874                }
1875                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1876                unsafe {
1877                    __null(#raw_mut repr);
1878                }
1879                repr
1880            }
1881            #new_method
1882            unsafe fn __raw(raw: *mut Self) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1883                #UnsafeExtern extern "C" {
1884                    #[link_name = #link_raw]
1885                    fn __raw(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>, raw: *mut ::cxx::core::ffi::c_void);
1886                }
1887                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1888                unsafe {
1889                    __raw(#raw_mut repr, raw.cast());
1890                }
1891                repr
1892            }
1893            unsafe fn __get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const Self {
1894                #UnsafeExtern extern "C" {
1895                    #[link_name = #link_get]
1896                    fn __get(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::core::ffi::c_void;
1897                }
1898                unsafe { __get(#raw_const repr).cast() }
1899            }
1900            unsafe fn __release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut Self {
1901                #UnsafeExtern extern "C" {
1902                    #[link_name = #link_release]
1903                    fn __release(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::core::ffi::c_void;
1904                }
1905                unsafe { __release(#raw_mut repr).cast() }
1906            }
1907            unsafe fn __drop(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) {
1908                #UnsafeExtern extern "C" {
1909                    #[link_name = #link_drop]
1910                    fn __drop(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1911                }
1912                unsafe {
1913                    __drop(#raw_mut repr);
1914                }
1915            }
1916        }
1917    }
1918}
1919
1920fn expand_shared_ptr(
1921    key: &NamedImplKey,
1922    types: &Types,
1923    conditional_impl: &ConditionalImpl,
1924) -> TokenStream {
1925    let ident = key.rust;
1926    let name = ident.to_string();
1927    let resolve = types.resolve(ident);
1928    let prefix = format!("cxxbridge1$shared_ptr${}$", resolve.name.to_symbol());
1929    let link_null = format!("{}null", prefix);
1930    let link_uninit = format!("{}uninit", prefix);
1931    let link_raw = format!("{}raw", prefix);
1932    let link_clone = format!("{}clone", prefix);
1933    let link_get = format!("{}get", prefix);
1934    let link_drop = format!("{}drop", prefix);
1935
1936    let (impl_generics, ty_generics) = generics::split_for_impl(key, conditional_impl, resolve);
1937
1938    let can_construct_from_value = types.is_maybe_trivial(ident);
1939    let new_method = if can_construct_from_value {
1940        Some(quote! {
1941            unsafe fn __new(value: Self, new: *mut ::cxx::core::ffi::c_void) {
1942                #UnsafeExtern extern "C" {
1943                    #[link_name = #link_uninit]
1944                    fn __uninit(new: *mut ::cxx::core::ffi::c_void) -> *mut ::cxx::core::ffi::c_void;
1945                }
1946                unsafe {
1947                    __uninit(new).cast::<#ident #ty_generics>().write(value);
1948                }
1949            }
1950        })
1951    } else {
1952        None
1953    };
1954
1955    let cfg = conditional_impl.cfg.into_attr();
1956    let begin_span = conditional_impl
1957        .explicit_impl
1958        .map_or(key.begin_span, |explicit| explicit.impl_token.span);
1959    let end_span = conditional_impl
1960        .explicit_impl
1961        .map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1962    let unsafe_token = format_ident!("unsafe", span = begin_span);
1963    let not_destructible_err = format!("{} is not destructible", display_namespaced(resolve.name));
1964
1965    quote_spanned! {end_span=>
1966        #cfg
1967        #[automatically_derived]
1968        #unsafe_token impl #impl_generics ::cxx::memory::SharedPtrTarget for #ident #ty_generics {
1969            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1970                f.write_str(#name)
1971            }
1972            unsafe fn __null(new: *mut ::cxx::core::ffi::c_void) {
1973                #UnsafeExtern extern "C" {
1974                    #[link_name = #link_null]
1975                    fn __null(new: *mut ::cxx::core::ffi::c_void);
1976                }
1977                unsafe {
1978                    __null(new);
1979                }
1980            }
1981            #new_method
1982            #[track_caller]
1983            unsafe fn __raw(new: *mut ::cxx::core::ffi::c_void, raw: *mut Self) {
1984                #UnsafeExtern extern "C" {
1985                    #[link_name = #link_raw]
1986                    fn __raw(new: *const ::cxx::core::ffi::c_void, raw: *mut ::cxx::core::ffi::c_void) -> ::cxx::core::primitive::bool;
1987                }
1988                if !unsafe { __raw(new, raw as *mut ::cxx::core::ffi::c_void) } {
1989                    ::cxx::core::panic!(#not_destructible_err);
1990                }
1991            }
1992            unsafe fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void) {
1993                #UnsafeExtern extern "C" {
1994                    #[link_name = #link_clone]
1995                    fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void);
1996                }
1997                unsafe {
1998                    __clone(this, new);
1999                }
2000            }
2001            unsafe fn __get(this: *const ::cxx::core::ffi::c_void) -> *const Self {
2002                #UnsafeExtern extern "C" {
2003                    #[link_name = #link_get]
2004                    fn __get(this: *const ::cxx::core::ffi::c_void) -> *const ::cxx::core::ffi::c_void;
2005                }
2006                unsafe { __get(this).cast() }
2007            }
2008            unsafe fn __drop(this: *mut ::cxx::core::ffi::c_void) {
2009                #UnsafeExtern extern "C" {
2010                    #[link_name = #link_drop]
2011                    fn __drop(this: *mut ::cxx::core::ffi::c_void);
2012                }
2013                unsafe {
2014                    __drop(this);
2015                }
2016            }
2017        }
2018    }
2019}
2020
2021fn expand_weak_ptr(
2022    key: &NamedImplKey,
2023    types: &Types,
2024    conditional_impl: &ConditionalImpl,
2025) -> TokenStream {
2026    let ident = key.rust;
2027    let name = ident.to_string();
2028    let resolve = types.resolve(ident);
2029    let prefix = format!("cxxbridge1$weak_ptr${}$", resolve.name.to_symbol());
2030    let link_null = format!("{}null", prefix);
2031    let link_clone = format!("{}clone", prefix);
2032    let link_downgrade = format!("{}downgrade", prefix);
2033    let link_upgrade = format!("{}upgrade", prefix);
2034    let link_drop = format!("{}drop", prefix);
2035
2036    let (impl_generics, ty_generics) = generics::split_for_impl(key, conditional_impl, resolve);
2037
2038    let cfg = conditional_impl.cfg.into_attr();
2039    let begin_span = conditional_impl
2040        .explicit_impl
2041        .map_or(key.begin_span, |explicit| explicit.impl_token.span);
2042    let end_span = conditional_impl
2043        .explicit_impl
2044        .map_or(key.end_span, |explicit| explicit.brace_token.span.join());
2045    let unsafe_token = format_ident!("unsafe", span = begin_span);
2046
2047    quote_spanned! {end_span=>
2048        #cfg
2049        #[automatically_derived]
2050        #unsafe_token impl #impl_generics ::cxx::memory::WeakPtrTarget for #ident #ty_generics {
2051            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
2052                f.write_str(#name)
2053            }
2054            unsafe fn __null(new: *mut ::cxx::core::ffi::c_void) {
2055                #UnsafeExtern extern "C" {
2056                    #[link_name = #link_null]
2057                    fn __null(new: *mut ::cxx::core::ffi::c_void);
2058                }
2059                unsafe {
2060                    __null(new);
2061                }
2062            }
2063            unsafe fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void) {
2064                #UnsafeExtern extern "C" {
2065                    #[link_name = #link_clone]
2066                    fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void);
2067                }
2068                unsafe {
2069                    __clone(this, new);
2070                }
2071            }
2072            unsafe fn __downgrade(shared: *const ::cxx::core::ffi::c_void, weak: *mut ::cxx::core::ffi::c_void) {
2073                #UnsafeExtern extern "C" {
2074                    #[link_name = #link_downgrade]
2075                    fn __downgrade(shared: *const ::cxx::core::ffi::c_void, weak: *mut ::cxx::core::ffi::c_void);
2076                }
2077                unsafe {
2078                    __downgrade(shared, weak);
2079                }
2080            }
2081            unsafe fn __upgrade(weak: *const ::cxx::core::ffi::c_void, shared: *mut ::cxx::core::ffi::c_void) {
2082                #UnsafeExtern extern "C" {
2083                    #[link_name = #link_upgrade]
2084                    fn __upgrade(weak: *const ::cxx::core::ffi::c_void, shared: *mut ::cxx::core::ffi::c_void);
2085                }
2086                unsafe {
2087                    __upgrade(weak, shared);
2088                }
2089            }
2090            unsafe fn __drop(this: *mut ::cxx::core::ffi::c_void) {
2091                #UnsafeExtern extern "C" {
2092                    #[link_name = #link_drop]
2093                    fn __drop(this: *mut ::cxx::core::ffi::c_void);
2094                }
2095                unsafe {
2096                    __drop(this);
2097                }
2098            }
2099        }
2100    }
2101}
2102
2103fn expand_cxx_vector(
2104    key: &NamedImplKey,
2105    conditional_impl: &ConditionalImpl,
2106    types: &Types,
2107) -> TokenStream {
2108    let elem = key.rust;
2109    let name = elem.to_string();
2110    let resolve = types.resolve(elem);
2111    let prefix = format!("cxxbridge1$std$vector${}$", resolve.name.to_symbol());
2112    let link_new = format!("{}new", prefix);
2113    let link_size = format!("{}size", prefix);
2114    let link_capacity = format!("{}capacity", prefix);
2115    let link_get_unchecked = format!("{}get_unchecked", prefix);
2116    let link_reserve = format!("{}reserve", prefix);
2117    let link_push_back = format!("{}push_back", prefix);
2118    let link_pop_back = format!("{}pop_back", prefix);
2119    let unique_ptr_prefix = format!(
2120        "cxxbridge1$unique_ptr$std$vector${}$",
2121        resolve.name.to_symbol(),
2122    );
2123    let link_unique_ptr_null = format!("{}null", unique_ptr_prefix);
2124    let link_unique_ptr_raw = format!("{}raw", unique_ptr_prefix);
2125    let link_unique_ptr_get = format!("{}get", unique_ptr_prefix);
2126    let link_unique_ptr_release = format!("{}release", unique_ptr_prefix);
2127    let link_unique_ptr_drop = format!("{}drop", unique_ptr_prefix);
2128
2129    let (impl_generics, ty_generics) = generics::split_for_impl(key, conditional_impl, resolve);
2130
2131    let cfg = conditional_impl.cfg.into_attr();
2132    let begin_span = conditional_impl
2133        .explicit_impl
2134        .map_or(key.begin_span, |explicit| explicit.impl_token.span);
2135    let end_span = conditional_impl
2136        .explicit_impl
2137        .map_or(key.end_span, |explicit| explicit.brace_token.span.join());
2138    let unsafe_token = format_ident!("unsafe", span = begin_span);
2139
2140    let can_pass_element_by_value = types.is_maybe_trivial(elem);
2141    let by_value_methods = if can_pass_element_by_value {
2142        Some(quote_spanned! {end_span=>
2143            unsafe fn __push_back(
2144                this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>,
2145                value: &mut ::cxx::core::mem::ManuallyDrop<Self>,
2146            ) {
2147                #UnsafeExtern extern "C" {
2148                    #[link_name = #link_push_back]
2149                    fn __push_back #impl_generics(
2150                        this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
2151                        value: *mut ::cxx::core::ffi::c_void,
2152                    );
2153                }
2154                unsafe {
2155                    __push_back(
2156                        this,
2157                        value as *mut ::cxx::core::mem::ManuallyDrop<Self> as *mut ::cxx::core::ffi::c_void,
2158                    );
2159                }
2160            }
2161            unsafe fn __pop_back(
2162                this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>,
2163                out: &mut ::cxx::core::mem::MaybeUninit<Self>,
2164            ) {
2165                #UnsafeExtern extern "C" {
2166                    #[link_name = #link_pop_back]
2167                    fn __pop_back #impl_generics(
2168                        this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
2169                        out: *mut ::cxx::core::ffi::c_void,
2170                    );
2171                }
2172                unsafe {
2173                    __pop_back(
2174                        this,
2175                        out as *mut ::cxx::core::mem::MaybeUninit<Self> as *mut ::cxx::core::ffi::c_void,
2176                    );
2177                }
2178            }
2179        })
2180    } else {
2181        None
2182    };
2183
2184    let raw_const = if rustversion::cfg!(since(1.82)) {
2185        quote_spanned!(end_span=> &raw const)
2186    } else {
2187        quote_spanned!(end_span=> &)
2188    };
2189    let raw_mut = if rustversion::cfg!(since(1.82)) {
2190        quote_spanned!(end_span=> &raw mut)
2191    } else {
2192        quote_spanned!(end_span=> &mut)
2193    };
2194
2195    quote_spanned! {end_span=>
2196        #cfg
2197        #[automatically_derived]
2198        #unsafe_token impl #impl_generics ::cxx::vector::VectorElement for #elem #ty_generics {
2199            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
2200                f.write_str(#name)
2201            }
2202            fn __vector_new() -> *mut ::cxx::CxxVector<Self> {
2203                #UnsafeExtern extern "C" {
2204                    #[link_name = #link_new]
2205                    fn __vector_new #impl_generics() -> *mut ::cxx::CxxVector<#elem #ty_generics>;
2206                }
2207                unsafe { __vector_new() }
2208            }
2209            fn __vector_size(v: &::cxx::CxxVector<Self>) -> usize {
2210                #UnsafeExtern extern "C" {
2211                    #[link_name = #link_size]
2212                    fn __vector_size #impl_generics(_: &::cxx::CxxVector<#elem #ty_generics>) -> usize;
2213                }
2214                unsafe { __vector_size(v) }
2215            }
2216            fn __vector_capacity(v: &::cxx::CxxVector<Self>) -> usize {
2217                #UnsafeExtern extern "C" {
2218                    #[link_name = #link_capacity]
2219                    fn __vector_capacity #impl_generics(_: &::cxx::CxxVector<#elem #ty_generics>) -> usize;
2220                }
2221                unsafe { __vector_capacity(v) }
2222            }
2223            unsafe fn __get_unchecked(v: *mut ::cxx::CxxVector<Self>, pos: usize) -> *mut Self {
2224                #UnsafeExtern extern "C" {
2225                    #[link_name = #link_get_unchecked]
2226                    fn __get_unchecked #impl_generics(
2227                        v: *mut ::cxx::CxxVector<#elem #ty_generics>,
2228                        pos: usize,
2229                    ) -> *mut ::cxx::core::ffi::c_void;
2230                }
2231                unsafe { __get_unchecked(v, pos) as *mut Self }
2232            }
2233            unsafe fn __reserve(v: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>, new_cap: usize) {
2234                #UnsafeExtern extern "C" {
2235                    #[link_name = #link_reserve]
2236                    fn __reserve #impl_generics(
2237                        v: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
2238                        new_cap: usize,
2239                    );
2240                }
2241                unsafe { __reserve(v, new_cap) }
2242            }
2243            #by_value_methods
2244            fn __unique_ptr_null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
2245                #UnsafeExtern extern "C" {
2246                    #[link_name = #link_unique_ptr_null]
2247                    fn __unique_ptr_null(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
2248                }
2249                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
2250                unsafe {
2251                    __unique_ptr_null(#raw_mut repr);
2252                }
2253                repr
2254            }
2255            unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<Self>) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
2256                #UnsafeExtern extern "C" {
2257                    #[link_name = #link_unique_ptr_raw]
2258                    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>);
2259                }
2260                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
2261                unsafe {
2262                    __unique_ptr_raw(#raw_mut repr, raw);
2263                }
2264                repr
2265            }
2266            unsafe fn __unique_ptr_get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<Self> {
2267                #UnsafeExtern extern "C" {
2268                    #[link_name = #link_unique_ptr_get]
2269                    fn __unique_ptr_get #impl_generics(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<#elem #ty_generics>;
2270                }
2271                unsafe { __unique_ptr_get(#raw_const repr) }
2272            }
2273            unsafe fn __unique_ptr_release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<Self> {
2274                #UnsafeExtern extern "C" {
2275                    #[link_name = #link_unique_ptr_release]
2276                    fn __unique_ptr_release #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<#elem #ty_generics>;
2277                }
2278                unsafe { __unique_ptr_release(#raw_mut repr) }
2279            }
2280            unsafe fn __unique_ptr_drop(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) {
2281                #UnsafeExtern extern "C" {
2282                    #[link_name = #link_unique_ptr_drop]
2283                    fn __unique_ptr_drop(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
2284                }
2285                unsafe {
2286                    __unique_ptr_drop(#raw_mut repr);
2287                }
2288            }
2289        }
2290    }
2291}
2292
2293fn expand_return_type(ret: &Option<Type>) -> TokenStream {
2294    match ret {
2295        Some(ret) => quote!(-> #ret),
2296        None => TokenStream::new(),
2297    }
2298}
2299
2300fn indirect_return(sig: &Signature, types: &Types, lang: Lang) -> bool {
2301    sig.ret.as_ref().is_some_and(|ret| {
2302        sig.throws
2303            || types.needs_indirect_abi(ret)
2304            || match lang {
2305                Lang::Cxx | Lang::CxxUnwind => types.contains_elided_lifetime(ret),
2306                Lang::Rust => false,
2307            }
2308    })
2309}
2310
2311fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream {
2312    match ty {
2313        Type::Ident(ident) if ident.rust == RustString => {
2314            let span = ident.rust.span();
2315            quote_spanned!(span=> ::cxx::private::RustString)
2316        }
2317        Type::RustBox(ty) | Type::UniquePtr(ty) => {
2318            let span = ty.name.span();
2319            if proper && types.is_considered_improper_ctype(&ty.inner) {
2320                quote_spanned!(span=> *mut ::cxx::core::ffi::c_void)
2321            } else {
2322                let inner = expand_extern_type(&ty.inner, types, proper);
2323                quote_spanned!(span=> *mut #inner)
2324            }
2325        }
2326        Type::RustVec(ty) => {
2327            let span = ty.name.span();
2328            let langle = ty.langle;
2329            let elem = expand_extern_type(&ty.inner, types, proper);
2330            let rangle = ty.rangle;
2331            quote_spanned!(span=> ::cxx::private::RustVec #langle #elem #rangle)
2332        }
2333        Type::Ref(ty) => {
2334            let ampersand = ty.ampersand;
2335            let lifetime = &ty.lifetime;
2336            let mutability = ty.mutability;
2337            match &ty.inner {
2338                Type::Ident(ident) if ident.rust == RustString => {
2339                    let span = ident.rust.span();
2340                    quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustString)
2341                }
2342                Type::RustVec(ty) => {
2343                    let span = ty.name.span();
2344                    let langle = ty.langle;
2345                    let inner = expand_extern_type(&ty.inner, types, proper);
2346                    let rangle = ty.rangle;
2347                    quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustVec #langle #inner #rangle)
2348                }
2349                inner if proper && types.is_considered_improper_ctype(inner) => {
2350                    let star = Token![*](ampersand.span);
2351                    match ty.mutable {
2352                        false => quote!(#star const ::cxx::core::ffi::c_void),
2353                        true => quote!(#star #mutability ::cxx::core::ffi::c_void),
2354                    }
2355                }
2356                _ => quote!(#ty),
2357            }
2358        }
2359        Type::Ptr(ty) => {
2360            if proper && types.is_considered_improper_ctype(&ty.inner) {
2361                let star = ty.star;
2362                let mutability = ty.mutability;
2363                let constness = ty.constness;
2364                quote!(#star #mutability #constness ::cxx::core::ffi::c_void)
2365            } else {
2366                quote!(#ty)
2367            }
2368        }
2369        Type::Str(ty) => {
2370            let span = ty.ampersand.span;
2371            let rust_str = Ident::new("RustStr", syn::spanned::Spanned::span(&ty.inner));
2372            quote_spanned!(span=> ::cxx::private::#rust_str)
2373        }
2374        Type::SliceRef(ty) => {
2375            let span = ty.ampersand.span;
2376            let rust_slice = Ident::new("RustSlice", ty.bracket.span.join());
2377            quote_spanned!(span=> ::cxx::private::#rust_slice)
2378        }
2379        _ => quote!(#ty),
2380    }
2381}
2382
2383fn expand_extern_return_type(
2384    sig: &Signature,
2385    types: &Types,
2386    proper: bool,
2387    lang: Lang,
2388) -> TokenStream {
2389    let ret = match &sig.ret {
2390        Some(ret) if !indirect_return(sig, types, lang) => ret,
2391        _ => return TokenStream::new(),
2392    };
2393    let ty = expand_extern_type(ret, types, proper);
2394    quote!(-> #ty)
2395}
2396
2397fn display_namespaced(name: &Pair) -> impl Display + '_ {
2398    struct Namespaced<'a>(&'a Pair);
2399
2400    impl<'a> Display for Namespaced<'a> {
2401        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2402            for segment in &self.0.namespace {
2403                write!(formatter, "{segment}::")?;
2404            }
2405            write!(formatter, "{}", self.0.cxx)
2406        }
2407    }
2408
2409    Namespaced(name)
2410}
2411
2412// #UnsafeExtern extern "C" {...}
2413// https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html#safe-items-with-unsafe-extern
2414struct UnsafeExtern;
2415
2416impl ToTokens for UnsafeExtern {
2417    fn to_tokens(&self, tokens: &mut TokenStream) {
2418        if rustversion::cfg!(since(1.82)) {
2419            Token![unsafe](Span::call_site()).to_tokens(tokens);
2420        }
2421    }
2422}
2423
2424// #[#UnsafeAttr(#ExportNameAttr = "...")]
2425// https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html#unsafe-attributes
2426struct UnsafeAttr;
2427struct ExportNameAttr;
2428
2429impl ToTokens for UnsafeAttr {
2430    fn to_tokens(&self, tokens: &mut TokenStream) {
2431        if rustversion::cfg!(since(1.82)) {
2432            Token![unsafe](Span::call_site()).to_tokens(tokens);
2433        } else {
2434            Ident::new("cfg_attr", Span::call_site()).to_tokens(tokens);
2435        }
2436    }
2437}
2438
2439impl ToTokens for ExportNameAttr {
2440    fn to_tokens(&self, tokens: &mut TokenStream) {
2441        if rustversion::cfg!(since(1.82)) {
2442            Ident::new("export_name", Span::call_site()).to_tokens(tokens);
2443        } else {
2444            tokens.extend(quote!(all(), export_name));
2445        }
2446    }
2447}