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