cxxbridge_macro/
expand.rs

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