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 ident = &alias.name.rust;
1268    let type_id = type_id(&alias.name);
1269    let begin_span = alias.type_token.span;
1270    let end_span = alias.semi_token.span;
1271    let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type::<);
1272    let end = quote_spanned!(end_span=> >);
1273
1274    let mut verify = quote! {
1275        const _: fn() = #begin #ident, #type_id #end;
1276    };
1277
1278    if types.required_trivial.contains_key(&alias.name.rust) {
1279        let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_kind::<);
1280        verify.extend(quote! {
1281            const _: fn() = #begin #ident, ::cxx::kind::Trivial #end;
1282        });
1283    }
1284
1285    verify
1286}
1287
1288fn type_id(name: &Pair) -> TokenStream {
1289    let namespace_segments = name.namespace.iter();
1290    let mut segments = Vec::with_capacity(namespace_segments.len() + 1);
1291    segments.extend(namespace_segments.cloned());
1292    segments.push(Ident::new(&name.cxx.to_string(), Span::call_site()));
1293    let qualified = QualifiedName { segments };
1294    crate::type_id::expand(Crate::Cxx, qualified)
1295}
1296
1297fn expand_rust_box(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream {
1298    let ident = key.rust;
1299    let resolve = types.resolve(ident);
1300    let link_prefix = format!("cxxbridge1$box${}$", resolve.name.to_symbol());
1301    let link_alloc = format!("{}alloc", link_prefix);
1302    let link_dealloc = format!("{}dealloc", link_prefix);
1303    let link_drop = format!("{}drop", link_prefix);
1304
1305    let local_prefix = format_ident!("{}__box_", ident);
1306    let local_alloc = format_ident!("{}alloc", local_prefix);
1307    let local_dealloc = format_ident!("{}dealloc", local_prefix);
1308    let local_drop = format_ident!("{}drop", local_prefix);
1309
1310    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1311
1312    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1313    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1314    let unsafe_token = format_ident!("unsafe", span = begin_span);
1315    let prevent_unwind_drop_label = format!("::{} as Drop>::drop", ident);
1316
1317    quote_spanned! {end_span=>
1318        #[automatically_derived]
1319        #[doc(hidden)]
1320        #unsafe_token impl #impl_generics ::cxx::private::ImplBox for #ident #ty_generics {}
1321        #[doc(hidden)]
1322        #[#UnsafeAttr(#ExportNameAttr = #link_alloc)]
1323        unsafe extern "C" fn #local_alloc #impl_generics() -> *mut ::cxx::core::mem::MaybeUninit<#ident #ty_generics> {
1324            // No prevent_unwind: the global allocator is not allowed to panic.
1325            //
1326            // TODO: replace with Box::new_uninit when stable.
1327            // https://doc.rust-lang.org/std/boxed/struct.Box.html#method.new_uninit
1328            // https://github.com/rust-lang/rust/issues/63291
1329            ::cxx::alloc::boxed::Box::into_raw(::cxx::alloc::boxed::Box::new(::cxx::core::mem::MaybeUninit::uninit()))
1330        }
1331        #[doc(hidden)]
1332        #[#UnsafeAttr(#ExportNameAttr = #link_dealloc)]
1333        unsafe extern "C" fn #local_dealloc #impl_generics(ptr: *mut ::cxx::core::mem::MaybeUninit<#ident #ty_generics>) {
1334            // No prevent_unwind: the global allocator is not allowed to panic.
1335            let _ = unsafe { ::cxx::alloc::boxed::Box::from_raw(ptr) };
1336        }
1337        #[doc(hidden)]
1338        #[#UnsafeAttr(#ExportNameAttr = #link_drop)]
1339        unsafe extern "C" fn #local_drop #impl_generics(this: *mut ::cxx::alloc::boxed::Box<#ident #ty_generics>) {
1340            let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1341            ::cxx::private::prevent_unwind(__fn, || unsafe { ::cxx::core::ptr::drop_in_place(this) });
1342        }
1343    }
1344}
1345
1346fn expand_rust_vec(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream {
1347    let elem = key.rust;
1348    let resolve = types.resolve(elem);
1349    let link_prefix = format!("cxxbridge1$rust_vec${}$", resolve.name.to_symbol());
1350    let link_new = format!("{}new", link_prefix);
1351    let link_drop = format!("{}drop", link_prefix);
1352    let link_len = format!("{}len", link_prefix);
1353    let link_capacity = format!("{}capacity", link_prefix);
1354    let link_data = format!("{}data", link_prefix);
1355    let link_reserve_total = format!("{}reserve_total", link_prefix);
1356    let link_set_len = format!("{}set_len", link_prefix);
1357    let link_truncate = format!("{}truncate", link_prefix);
1358
1359    let local_prefix = format_ident!("{}__vec_", elem);
1360    let local_new = format_ident!("{}new", local_prefix);
1361    let local_drop = format_ident!("{}drop", local_prefix);
1362    let local_len = format_ident!("{}len", local_prefix);
1363    let local_capacity = format_ident!("{}capacity", local_prefix);
1364    let local_data = format_ident!("{}data", local_prefix);
1365    let local_reserve_total = format_ident!("{}reserve_total", local_prefix);
1366    let local_set_len = format_ident!("{}set_len", local_prefix);
1367    let local_truncate = format_ident!("{}truncate", local_prefix);
1368
1369    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1370
1371    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1372    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1373    let unsafe_token = format_ident!("unsafe", span = begin_span);
1374    let prevent_unwind_drop_label = format!("::{} as Drop>::drop", elem);
1375
1376    quote_spanned! {end_span=>
1377        #[automatically_derived]
1378        #[doc(hidden)]
1379        #unsafe_token impl #impl_generics ::cxx::private::ImplVec for #elem #ty_generics {}
1380        #[doc(hidden)]
1381        #[#UnsafeAttr(#ExportNameAttr = #link_new)]
1382        unsafe extern "C" fn #local_new #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>) {
1383            // No prevent_unwind: cannot panic.
1384            unsafe {
1385                ::cxx::core::ptr::write(this, ::cxx::private::RustVec::new());
1386            }
1387        }
1388        #[doc(hidden)]
1389        #[#UnsafeAttr(#ExportNameAttr = #link_drop)]
1390        unsafe extern "C" fn #local_drop #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>) {
1391            let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1392            ::cxx::private::prevent_unwind(
1393                __fn,
1394                || unsafe { ::cxx::core::ptr::drop_in_place(this) },
1395            );
1396        }
1397        #[doc(hidden)]
1398        #[#UnsafeAttr(#ExportNameAttr = #link_len)]
1399        unsafe extern "C" fn #local_len #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> usize {
1400            // No prevent_unwind: cannot panic.
1401            unsafe { (*this).len() }
1402        }
1403        #[doc(hidden)]
1404        #[#UnsafeAttr(#ExportNameAttr = #link_capacity)]
1405        unsafe extern "C" fn #local_capacity #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> usize {
1406            // No prevent_unwind: cannot panic.
1407            unsafe { (*this).capacity() }
1408        }
1409        #[doc(hidden)]
1410        #[#UnsafeAttr(#ExportNameAttr = #link_data)]
1411        unsafe extern "C" fn #local_data #impl_generics(this: *const ::cxx::private::RustVec<#elem #ty_generics>) -> *const #elem #ty_generics {
1412            // No prevent_unwind: cannot panic.
1413            unsafe { (*this).as_ptr() }
1414        }
1415        #[doc(hidden)]
1416        #[#UnsafeAttr(#ExportNameAttr = #link_reserve_total)]
1417        unsafe extern "C" fn #local_reserve_total #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, new_cap: usize) {
1418            // No prevent_unwind: the global allocator is not allowed to panic.
1419            unsafe {
1420                (*this).reserve_total(new_cap);
1421            }
1422        }
1423        #[doc(hidden)]
1424        #[#UnsafeAttr(#ExportNameAttr = #link_set_len)]
1425        unsafe extern "C" fn #local_set_len #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, len: usize) {
1426            // No prevent_unwind: cannot panic.
1427            unsafe {
1428                (*this).set_len(len);
1429            }
1430        }
1431        #[doc(hidden)]
1432        #[#UnsafeAttr(#ExportNameAttr = #link_truncate)]
1433        unsafe extern "C" fn #local_truncate #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, len: usize) {
1434            let __fn = concat!("<", module_path!(), #prevent_unwind_drop_label);
1435            ::cxx::private::prevent_unwind(
1436                __fn,
1437                || unsafe { (*this).truncate(len) },
1438            );
1439        }
1440    }
1441}
1442
1443fn expand_unique_ptr(
1444    key: NamedImplKey,
1445    types: &Types,
1446    explicit_impl: Option<&Impl>,
1447) -> TokenStream {
1448    let ident = key.rust;
1449    let name = ident.to_string();
1450    let resolve = types.resolve(ident);
1451    let prefix = format!("cxxbridge1$unique_ptr${}$", resolve.name.to_symbol());
1452    let link_null = format!("{}null", prefix);
1453    let link_uninit = format!("{}uninit", prefix);
1454    let link_raw = format!("{}raw", prefix);
1455    let link_get = format!("{}get", prefix);
1456    let link_release = format!("{}release", prefix);
1457    let link_drop = format!("{}drop", prefix);
1458
1459    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1460
1461    let can_construct_from_value = types.is_maybe_trivial(ident);
1462    let new_method = if can_construct_from_value {
1463        Some(quote! {
1464            fn __new(value: Self) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1465                #UnsafeExtern extern "C" {
1466                    #[link_name = #link_uninit]
1467                    fn __uninit(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::core::ffi::c_void;
1468                }
1469                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1470                unsafe {
1471                    __uninit(&mut repr).cast::<#ident #ty_generics>().write(value);
1472                }
1473                repr
1474            }
1475        })
1476    } else {
1477        None
1478    };
1479
1480    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1481    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1482    let unsafe_token = format_ident!("unsafe", span = begin_span);
1483
1484    quote_spanned! {end_span=>
1485        #[automatically_derived]
1486        #unsafe_token impl #impl_generics ::cxx::private::UniquePtrTarget for #ident #ty_generics {
1487            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1488                f.write_str(#name)
1489            }
1490            fn __null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1491                #UnsafeExtern extern "C" {
1492                    #[link_name = #link_null]
1493                    fn __null(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1494                }
1495                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1496                unsafe {
1497                    __null(&mut repr);
1498                }
1499                repr
1500            }
1501            #new_method
1502            unsafe fn __raw(raw: *mut Self) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1503                #UnsafeExtern extern "C" {
1504                    #[link_name = #link_raw]
1505                    fn __raw(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>, raw: *mut ::cxx::core::ffi::c_void);
1506                }
1507                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1508                unsafe {
1509                    __raw(&mut repr, raw.cast());
1510                }
1511                repr
1512            }
1513            unsafe fn __get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const Self {
1514                #UnsafeExtern extern "C" {
1515                    #[link_name = #link_get]
1516                    fn __get(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::core::ffi::c_void;
1517                }
1518                unsafe { __get(&repr).cast() }
1519            }
1520            unsafe fn __release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut Self {
1521                #UnsafeExtern extern "C" {
1522                    #[link_name = #link_release]
1523                    fn __release(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::core::ffi::c_void;
1524                }
1525                unsafe { __release(&mut repr).cast() }
1526            }
1527            unsafe fn __drop(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) {
1528                #UnsafeExtern extern "C" {
1529                    #[link_name = #link_drop]
1530                    fn __drop(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1531                }
1532                unsafe {
1533                    __drop(&mut repr);
1534                }
1535            }
1536        }
1537    }
1538}
1539
1540fn expand_shared_ptr(
1541    key: NamedImplKey,
1542    types: &Types,
1543    explicit_impl: Option<&Impl>,
1544) -> TokenStream {
1545    let ident = key.rust;
1546    let name = ident.to_string();
1547    let resolve = types.resolve(ident);
1548    let prefix = format!("cxxbridge1$shared_ptr${}$", resolve.name.to_symbol());
1549    let link_null = format!("{}null", prefix);
1550    let link_uninit = format!("{}uninit", prefix);
1551    let link_clone = format!("{}clone", prefix);
1552    let link_get = format!("{}get", prefix);
1553    let link_drop = format!("{}drop", prefix);
1554
1555    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1556
1557    let can_construct_from_value = types.is_maybe_trivial(ident);
1558    let new_method = if can_construct_from_value {
1559        Some(quote! {
1560            unsafe fn __new(value: Self, new: *mut ::cxx::core::ffi::c_void) {
1561                #UnsafeExtern extern "C" {
1562                    #[link_name = #link_uninit]
1563                    fn __uninit(new: *mut ::cxx::core::ffi::c_void) -> *mut ::cxx::core::ffi::c_void;
1564                }
1565                unsafe {
1566                    __uninit(new).cast::<#ident #ty_generics>().write(value);
1567                }
1568            }
1569        })
1570    } else {
1571        None
1572    };
1573
1574    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1575    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1576    let unsafe_token = format_ident!("unsafe", span = begin_span);
1577
1578    quote_spanned! {end_span=>
1579        #[automatically_derived]
1580        #unsafe_token impl #impl_generics ::cxx::private::SharedPtrTarget for #ident #ty_generics {
1581            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1582                f.write_str(#name)
1583            }
1584            unsafe fn __null(new: *mut ::cxx::core::ffi::c_void) {
1585                #UnsafeExtern extern "C" {
1586                    #[link_name = #link_null]
1587                    fn __null(new: *mut ::cxx::core::ffi::c_void);
1588                }
1589                unsafe {
1590                    __null(new);
1591                }
1592            }
1593            #new_method
1594            unsafe fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void) {
1595                #UnsafeExtern extern "C" {
1596                    #[link_name = #link_clone]
1597                    fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void);
1598                }
1599                unsafe {
1600                    __clone(this, new);
1601                }
1602            }
1603            unsafe fn __get(this: *const ::cxx::core::ffi::c_void) -> *const Self {
1604                #UnsafeExtern extern "C" {
1605                    #[link_name = #link_get]
1606                    fn __get(this: *const ::cxx::core::ffi::c_void) -> *const ::cxx::core::ffi::c_void;
1607                }
1608                unsafe { __get(this).cast() }
1609            }
1610            unsafe fn __drop(this: *mut ::cxx::core::ffi::c_void) {
1611                #UnsafeExtern extern "C" {
1612                    #[link_name = #link_drop]
1613                    fn __drop(this: *mut ::cxx::core::ffi::c_void);
1614                }
1615                unsafe {
1616                    __drop(this);
1617                }
1618            }
1619        }
1620    }
1621}
1622
1623fn expand_weak_ptr(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl>) -> TokenStream {
1624    let ident = key.rust;
1625    let name = ident.to_string();
1626    let resolve = types.resolve(ident);
1627    let prefix = format!("cxxbridge1$weak_ptr${}$", resolve.name.to_symbol());
1628    let link_null = format!("{}null", prefix);
1629    let link_clone = format!("{}clone", prefix);
1630    let link_downgrade = format!("{}downgrade", prefix);
1631    let link_upgrade = format!("{}upgrade", prefix);
1632    let link_drop = format!("{}drop", prefix);
1633
1634    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1635
1636    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1637    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1638    let unsafe_token = format_ident!("unsafe", span = begin_span);
1639
1640    quote_spanned! {end_span=>
1641        #[automatically_derived]
1642        #unsafe_token impl #impl_generics ::cxx::private::WeakPtrTarget for #ident #ty_generics {
1643            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1644                f.write_str(#name)
1645            }
1646            unsafe fn __null(new: *mut ::cxx::core::ffi::c_void) {
1647                #UnsafeExtern extern "C" {
1648                    #[link_name = #link_null]
1649                    fn __null(new: *mut ::cxx::core::ffi::c_void);
1650                }
1651                unsafe {
1652                    __null(new);
1653                }
1654            }
1655            unsafe fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void) {
1656                #UnsafeExtern extern "C" {
1657                    #[link_name = #link_clone]
1658                    fn __clone(this: *const ::cxx::core::ffi::c_void, new: *mut ::cxx::core::ffi::c_void);
1659                }
1660                unsafe {
1661                    __clone(this, new);
1662                }
1663            }
1664            unsafe fn __downgrade(shared: *const ::cxx::core::ffi::c_void, weak: *mut ::cxx::core::ffi::c_void) {
1665                #UnsafeExtern extern "C" {
1666                    #[link_name = #link_downgrade]
1667                    fn __downgrade(shared: *const ::cxx::core::ffi::c_void, weak: *mut ::cxx::core::ffi::c_void);
1668                }
1669                unsafe {
1670                    __downgrade(shared, weak);
1671                }
1672            }
1673            unsafe fn __upgrade(weak: *const ::cxx::core::ffi::c_void, shared: *mut ::cxx::core::ffi::c_void) {
1674                #UnsafeExtern extern "C" {
1675                    #[link_name = #link_upgrade]
1676                    fn __upgrade(weak: *const ::cxx::core::ffi::c_void, shared: *mut ::cxx::core::ffi::c_void);
1677                }
1678                unsafe {
1679                    __upgrade(weak, shared);
1680                }
1681            }
1682            unsafe fn __drop(this: *mut ::cxx::core::ffi::c_void) {
1683                #UnsafeExtern extern "C" {
1684                    #[link_name = #link_drop]
1685                    fn __drop(this: *mut ::cxx::core::ffi::c_void);
1686                }
1687                unsafe {
1688                    __drop(this);
1689                }
1690            }
1691        }
1692    }
1693}
1694
1695fn expand_cxx_vector(
1696    key: NamedImplKey,
1697    explicit_impl: Option<&Impl>,
1698    types: &Types,
1699) -> TokenStream {
1700    let elem = key.rust;
1701    let name = elem.to_string();
1702    let resolve = types.resolve(elem);
1703    let prefix = format!("cxxbridge1$std$vector${}$", resolve.name.to_symbol());
1704    let link_new = format!("{}new", prefix);
1705    let link_size = format!("{}size", prefix);
1706    let link_get_unchecked = format!("{}get_unchecked", prefix);
1707    let link_push_back = format!("{}push_back", prefix);
1708    let link_pop_back = format!("{}pop_back", prefix);
1709    let unique_ptr_prefix = format!(
1710        "cxxbridge1$unique_ptr$std$vector${}$",
1711        resolve.name.to_symbol(),
1712    );
1713    let link_unique_ptr_null = format!("{}null", unique_ptr_prefix);
1714    let link_unique_ptr_raw = format!("{}raw", unique_ptr_prefix);
1715    let link_unique_ptr_get = format!("{}get", unique_ptr_prefix);
1716    let link_unique_ptr_release = format!("{}release", unique_ptr_prefix);
1717    let link_unique_ptr_drop = format!("{}drop", unique_ptr_prefix);
1718
1719    let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
1720
1721    let begin_span = explicit_impl.map_or(key.begin_span, |explicit| explicit.impl_token.span);
1722    let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span.join());
1723    let unsafe_token = format_ident!("unsafe", span = begin_span);
1724
1725    let can_pass_element_by_value = types.is_maybe_trivial(elem);
1726    let by_value_methods = if can_pass_element_by_value {
1727        Some(quote_spanned! {end_span=>
1728            unsafe fn __push_back(
1729                this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>,
1730                value: &mut ::cxx::core::mem::ManuallyDrop<Self>,
1731            ) {
1732                #UnsafeExtern extern "C" {
1733                    #[link_name = #link_push_back]
1734                    fn __push_back #impl_generics(
1735                        this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
1736                        value: *mut ::cxx::core::ffi::c_void,
1737                    );
1738                }
1739                unsafe {
1740                    __push_back(
1741                        this,
1742                        value as *mut ::cxx::core::mem::ManuallyDrop<Self> as *mut ::cxx::core::ffi::c_void,
1743                    );
1744                }
1745            }
1746            unsafe fn __pop_back(
1747                this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>,
1748                out: &mut ::cxx::core::mem::MaybeUninit<Self>,
1749            ) {
1750                #UnsafeExtern extern "C" {
1751                    #[link_name = #link_pop_back]
1752                    fn __pop_back #impl_generics(
1753                        this: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
1754                        out: *mut ::cxx::core::ffi::c_void,
1755                    );
1756                }
1757                unsafe {
1758                    __pop_back(
1759                        this,
1760                        out as *mut ::cxx::core::mem::MaybeUninit<Self> as *mut ::cxx::core::ffi::c_void,
1761                    );
1762                }
1763            }
1764        })
1765    } else {
1766        None
1767    };
1768
1769    quote_spanned! {end_span=>
1770        #[automatically_derived]
1771        #unsafe_token impl #impl_generics ::cxx::private::VectorElement for #elem #ty_generics {
1772            fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
1773                f.write_str(#name)
1774            }
1775            fn __vector_new() -> *mut ::cxx::CxxVector<Self> {
1776                #UnsafeExtern extern "C" {
1777                    #[link_name = #link_new]
1778                    fn __vector_new #impl_generics() -> *mut ::cxx::CxxVector<#elem #ty_generics>;
1779                }
1780                unsafe { __vector_new() }
1781            }
1782            fn __vector_size(v: &::cxx::CxxVector<Self>) -> usize {
1783                #UnsafeExtern extern "C" {
1784                    #[link_name = #link_size]
1785                    fn __vector_size #impl_generics(_: &::cxx::CxxVector<#elem #ty_generics>) -> usize;
1786                }
1787                unsafe { __vector_size(v) }
1788            }
1789            unsafe fn __get_unchecked(v: *mut ::cxx::CxxVector<Self>, pos: usize) -> *mut Self {
1790                #UnsafeExtern extern "C" {
1791                    #[link_name = #link_get_unchecked]
1792                    fn __get_unchecked #impl_generics(
1793                        v: *mut ::cxx::CxxVector<#elem #ty_generics>,
1794                        pos: usize,
1795                    ) -> *mut ::cxx::core::ffi::c_void;
1796                }
1797                unsafe { __get_unchecked(v, pos) as *mut Self }
1798            }
1799            #by_value_methods
1800            fn __unique_ptr_null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1801                #UnsafeExtern extern "C" {
1802                    #[link_name = #link_unique_ptr_null]
1803                    fn __unique_ptr_null(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1804                }
1805                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1806                unsafe {
1807                    __unique_ptr_null(&mut repr);
1808                }
1809                repr
1810            }
1811            unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<Self>) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
1812                #UnsafeExtern extern "C" {
1813                    #[link_name = #link_unique_ptr_raw]
1814                    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>);
1815                }
1816                let mut repr = ::cxx::core::mem::MaybeUninit::uninit();
1817                unsafe {
1818                    __unique_ptr_raw(&mut repr, raw);
1819                }
1820                repr
1821            }
1822            unsafe fn __unique_ptr_get(repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<Self> {
1823                #UnsafeExtern extern "C" {
1824                    #[link_name = #link_unique_ptr_get]
1825                    fn __unique_ptr_get #impl_generics(this: *const ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *const ::cxx::CxxVector<#elem #ty_generics>;
1826                }
1827                unsafe { __unique_ptr_get(&repr) }
1828            }
1829            unsafe fn __unique_ptr_release(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<Self> {
1830                #UnsafeExtern extern "C" {
1831                    #[link_name = #link_unique_ptr_release]
1832                    fn __unique_ptr_release #impl_generics(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) -> *mut ::cxx::CxxVector<#elem #ty_generics>;
1833                }
1834                unsafe { __unique_ptr_release(&mut repr) }
1835            }
1836            unsafe fn __unique_ptr_drop(mut repr: ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>) {
1837                #UnsafeExtern extern "C" {
1838                    #[link_name = #link_unique_ptr_drop]
1839                    fn __unique_ptr_drop(this: *mut ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void>);
1840                }
1841                unsafe {
1842                    __unique_ptr_drop(&mut repr);
1843                }
1844            }
1845        }
1846    }
1847}
1848
1849fn expand_return_type(ret: &Option<Type>) -> TokenStream {
1850    match ret {
1851        Some(ret) => quote!(-> #ret),
1852        None => TokenStream::new(),
1853    }
1854}
1855
1856fn indirect_return(sig: &Signature, types: &Types) -> bool {
1857    sig.ret
1858        .as_ref()
1859        .is_some_and(|ret| sig.throws || types.needs_indirect_abi(ret))
1860}
1861
1862fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream {
1863    match ty {
1864        Type::Ident(ident) if ident.rust == RustString => {
1865            let span = ident.rust.span();
1866            quote_spanned!(span=> ::cxx::private::RustString)
1867        }
1868        Type::RustBox(ty) | Type::UniquePtr(ty) => {
1869            let span = ty.name.span();
1870            if proper && types.is_considered_improper_ctype(&ty.inner) {
1871                quote_spanned!(span=> *mut ::cxx::core::ffi::c_void)
1872            } else {
1873                let inner = expand_extern_type(&ty.inner, types, proper);
1874                quote_spanned!(span=> *mut #inner)
1875            }
1876        }
1877        Type::RustVec(ty) => {
1878            let span = ty.name.span();
1879            let langle = ty.langle;
1880            let elem = expand_extern_type(&ty.inner, types, proper);
1881            let rangle = ty.rangle;
1882            quote_spanned!(span=> ::cxx::private::RustVec #langle #elem #rangle)
1883        }
1884        Type::Ref(ty) => {
1885            let ampersand = ty.ampersand;
1886            let lifetime = &ty.lifetime;
1887            let mutability = ty.mutability;
1888            match &ty.inner {
1889                Type::Ident(ident) if ident.rust == RustString => {
1890                    let span = ident.rust.span();
1891                    quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustString)
1892                }
1893                Type::RustVec(ty) => {
1894                    let span = ty.name.span();
1895                    let langle = ty.langle;
1896                    let inner = expand_extern_type(&ty.inner, types, proper);
1897                    let rangle = ty.rangle;
1898                    quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustVec #langle #inner #rangle)
1899                }
1900                inner if proper && types.is_considered_improper_ctype(inner) => {
1901                    let star = Token![*](ampersand.span);
1902                    match ty.mutable {
1903                        false => quote!(#star const ::cxx::core::ffi::c_void),
1904                        true => quote!(#star #mutability ::cxx::core::ffi::c_void),
1905                    }
1906                }
1907                _ => quote!(#ty),
1908            }
1909        }
1910        Type::Ptr(ty) => {
1911            if proper && types.is_considered_improper_ctype(&ty.inner) {
1912                let star = ty.star;
1913                let mutability = ty.mutability;
1914                let constness = ty.constness;
1915                quote!(#star #mutability #constness ::cxx::core::ffi::c_void)
1916            } else {
1917                quote!(#ty)
1918            }
1919        }
1920        Type::Str(ty) => {
1921            let span = ty.ampersand.span;
1922            let rust_str = Ident::new("RustStr", syn::spanned::Spanned::span(&ty.inner));
1923            quote_spanned!(span=> ::cxx::private::#rust_str)
1924        }
1925        Type::SliceRef(ty) => {
1926            let span = ty.ampersand.span;
1927            let rust_slice = Ident::new("RustSlice", ty.bracket.span.join());
1928            quote_spanned!(span=> ::cxx::private::#rust_slice)
1929        }
1930        _ => quote!(#ty),
1931    }
1932}
1933
1934fn expand_extern_return_type(ret: &Option<Type>, types: &Types, proper: bool) -> TokenStream {
1935    let ret = match ret {
1936        Some(ret) if !types.needs_indirect_abi(ret) => ret,
1937        _ => return TokenStream::new(),
1938    };
1939    let ty = expand_extern_type(ret, types, proper);
1940    quote!(-> #ty)
1941}
1942
1943// #UnsafeExtern extern "C" {...}
1944// https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html#safe-items-with-unsafe-extern
1945struct UnsafeExtern;
1946
1947impl ToTokens for UnsafeExtern {
1948    fn to_tokens(&self, tokens: &mut TokenStream) {
1949        if rustversion::cfg!(since(1.82)) {
1950            Token![unsafe](Span::call_site()).to_tokens(tokens);
1951        }
1952    }
1953}
1954
1955// #[#UnsafeAttr(#ExportNameAttr = "...")]
1956// https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html#unsafe-attributes
1957struct UnsafeAttr;
1958struct ExportNameAttr;
1959
1960impl ToTokens for UnsafeAttr {
1961    fn to_tokens(&self, tokens: &mut TokenStream) {
1962        if rustversion::cfg!(since(1.82)) {
1963            Token![unsafe](Span::call_site()).to_tokens(tokens);
1964        } else {
1965            Ident::new("cfg_attr", Span::call_site()).to_tokens(tokens);
1966        }
1967    }
1968}
1969
1970impl ToTokens for ExportNameAttr {
1971    fn to_tokens(&self, tokens: &mut TokenStream) {
1972        if rustversion::cfg!(since(1.82)) {
1973            Ident::new("export_name", Span::call_site()).to_tokens(tokens);
1974        } else {
1975            tokens.extend(quote!(all(), export_name));
1976        }
1977    }
1978}