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