cxxbridge_macro/
expand.rs

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