1use crate::syntax::attrs::OtherAttrs;
2use crate::syntax::cfg::CfgExpr;
3use crate::syntax::discriminant::DiscriminantSet;
4use crate::syntax::file::{Item, ItemForeignMod};
5use crate::syntax::report::Errors;
6use crate::syntax::repr::Repr;
7use crate::syntax::Atom::*;
8use crate::syntax::{
9 attrs, error, Api, Array, Derive, Doc, Enum, EnumRepr, ExternFn, ExternType, FnKind,
10 ForeignName, Impl, Include, IncludeKind, Lang, Lifetimes, NamedType, Namespace, Pair, Ptr,
11 Receiver, Ref, Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var, Variant,
12};
13use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
14use quote::{format_ident, quote, quote_spanned};
15use std::mem;
16use syn::parse::{ParseStream, Parser};
17use syn::punctuated::Punctuated;
18use syn::{
19 Abi, Attribute, Error, Expr, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
20 GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lit, LitStr,
21 Pat, PathArguments, Result, ReturnType, Signature as RustSignature, Token, TraitBound,
22 TraitBoundModifier, Type as RustType, TypeArray, TypeBareFn, TypeParamBound, TypePath, TypePtr,
23 TypeReference, Variant as RustVariant, Visibility,
24};
25
26pub(crate) mod kw {
27 syn::custom_keyword!(Pin);
28 syn::custom_keyword!(Result);
29}
30
31pub(crate) fn parse_items(
32 cx: &mut Errors,
33 items: Vec<Item>,
34 trusted: bool,
35 namespace: &Namespace,
36) -> Vec<Api> {
37 let mut apis = Vec::new();
38 for item in items {
39 match item {
40 Item::Struct(item) => match parse_struct(cx, item, namespace) {
41 Ok(strct) => apis.push(strct),
42 Err(err) => cx.push(err),
43 },
44 Item::Enum(item) => apis.push(parse_enum(cx, item, namespace)),
45 Item::ForeignMod(foreign_mod) => {
46 parse_foreign_mod(cx, foreign_mod, &mut apis, trusted, namespace);
47 }
48 Item::Impl(item) => match parse_impl(cx, item) {
49 Ok(imp) => apis.push(imp),
50 Err(err) => cx.push(err),
51 },
52 Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
53 Item::Other(item) => cx.error(item, "unsupported item"),
54 }
55 }
56 apis
57}
58
59fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> Result<Api> {
60 let mut cfg = CfgExpr::Unconditional;
61 let mut doc = Doc::new();
62 let mut derives = Vec::new();
63 let mut repr = None;
64 let mut namespace = namespace.clone();
65 let mut cxx_name = None;
66 let mut rust_name = None;
67 let attrs = attrs::parse(
68 cx,
69 mem::take(&mut item.attrs),
70 attrs::Parser {
71 cfg: Some(&mut cfg),
72 doc: Some(&mut doc),
73 derives: Some(&mut derives),
74 repr: Some(&mut repr),
75 namespace: Some(&mut namespace),
76 cxx_name: Some(&mut cxx_name),
77 rust_name: Some(&mut rust_name),
78 ..Default::default()
79 },
80 );
81
82 let align = match repr {
83 Some(Repr::Align(align)) => Some(align),
84 Some(Repr::Atom(_atom, span)) => {
85 cx.push(Error::new(span, "unsupported alignment on a struct"));
86 None
87 }
88 None => None,
89 };
90
91 let named_fields = match item.fields {
92 Fields::Named(fields) => fields,
93 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
94 Fields::Unnamed(_) => {
95 return Err(Error::new_spanned(item, "tuple structs are not supported"));
96 }
97 };
98
99 let mut lifetimes = Punctuated::new();
100 let mut has_unsupported_generic_param = false;
101 for pair in item.generics.params.into_pairs() {
102 let (param, punct) = pair.into_tuple();
103 match param {
104 GenericParam::Lifetime(param) => {
105 if !param.bounds.is_empty() && !has_unsupported_generic_param {
106 let msg = "lifetime parameter with bounds is not supported yet";
107 cx.error(¶m, msg);
108 has_unsupported_generic_param = true;
109 }
110 lifetimes.push_value(param.lifetime);
111 if let Some(punct) = punct {
112 lifetimes.push_punct(punct);
113 }
114 }
115 GenericParam::Type(param) => {
116 if !has_unsupported_generic_param {
117 let msg = "struct with generic type parameter is not supported yet";
118 cx.error(¶m, msg);
119 has_unsupported_generic_param = true;
120 }
121 }
122 GenericParam::Const(param) => {
123 if !has_unsupported_generic_param {
124 let msg = "struct with const generic parameter is not supported yet";
125 cx.error(¶m, msg);
126 has_unsupported_generic_param = true;
127 }
128 }
129 }
130 }
131
132 if let Some(where_clause) = &item.generics.where_clause {
133 cx.error(
134 where_clause,
135 "struct with where-clause is not supported yet",
136 );
137 }
138
139 let mut fields = Vec::new();
140 for field in named_fields.named {
141 let ident = field.ident.unwrap();
142 let mut cfg = CfgExpr::Unconditional;
143 let mut doc = Doc::new();
144 let mut cxx_name = None;
145 let mut rust_name = None;
146 let attrs = attrs::parse(
147 cx,
148 field.attrs,
149 attrs::Parser {
150 cfg: Some(&mut cfg),
151 doc: Some(&mut doc),
152 cxx_name: Some(&mut cxx_name),
153 rust_name: Some(&mut rust_name),
154 ..Default::default()
155 },
156 );
157 let ty = match parse_type(&field.ty) {
158 Ok(ty) => ty,
159 Err(err) => {
160 cx.push(err);
161 continue;
162 }
163 };
164 let visibility = visibility_pub(&field.vis, ident.span());
165 let name = pair(Namespace::default(), &ident, cxx_name, rust_name);
166 let colon_token = field.colon_token.unwrap();
167 fields.push(Var {
168 cfg,
169 doc,
170 attrs,
171 visibility,
172 name,
173 colon_token,
174 ty,
175 });
176 }
177
178 let struct_token = item.struct_token;
179 let visibility = visibility_pub(&item.vis, struct_token.span);
180 let name = pair(namespace, &item.ident, cxx_name, rust_name);
181 let generics = Lifetimes {
182 lt_token: item.generics.lt_token,
183 lifetimes,
184 gt_token: item.generics.gt_token,
185 };
186 let brace_token = named_fields.brace_token;
187
188 Ok(Api::Struct(Struct {
189 cfg,
190 doc,
191 derives,
192 align,
193 attrs,
194 visibility,
195 struct_token,
196 name,
197 generics,
198 brace_token,
199 fields,
200 }))
201}
202
203fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api {
204 let mut cfg = CfgExpr::Unconditional;
205 let mut doc = Doc::new();
206 let mut derives = Vec::new();
207 let mut repr = None;
208 let mut namespace = namespace.clone();
209 let mut cxx_name = None;
210 let mut rust_name = None;
211 let attrs = attrs::parse(
212 cx,
213 item.attrs,
214 attrs::Parser {
215 cfg: Some(&mut cfg),
216 doc: Some(&mut doc),
217 derives: Some(&mut derives),
218 repr: Some(&mut repr),
219 namespace: Some(&mut namespace),
220 cxx_name: Some(&mut cxx_name),
221 rust_name: Some(&mut rust_name),
222 ..Default::default()
223 },
224 );
225
226 if !item.generics.params.is_empty() {
227 let vis = &item.vis;
228 let enum_token = item.enum_token;
229 let ident = &item.ident;
230 let generics = &item.generics;
231 let span = quote!(#vis #enum_token #ident #generics);
232 cx.error(span, "enum with generic parameters is not supported");
233 } else if let Some(where_clause) = &item.generics.where_clause {
234 cx.error(where_clause, "enum with where-clause is not supported");
235 }
236
237 let repr = match repr {
238 Some(Repr::Atom(atom, _span)) => Some(atom),
239 Some(Repr::Align(align)) => {
240 cx.error(align, "C++ does not support custom alignment on an enum");
241 None
242 }
243 None => None,
244 };
245
246 let mut variants = Vec::new();
247 let mut discriminants = DiscriminantSet::new(repr);
248 for variant in item.variants {
249 match parse_variant(cx, variant, &mut discriminants) {
250 Ok(variant) => variants.push(variant),
251 Err(err) => cx.push(err),
252 }
253 }
254
255 let enum_token = item.enum_token;
256 let visibility = visibility_pub(&item.vis, enum_token.span);
257 let brace_token = item.brace_token;
258
259 let explicit_repr = repr.is_some();
260 let mut repr = U8;
261 match discriminants.inferred_repr() {
262 Ok(inferred) => repr = inferred,
263 Err(err) => {
264 let span = quote_spanned!(brace_token.span=> #enum_token {});
265 cx.error(span, err);
266 variants.clear();
267 }
268 }
269
270 let name = pair(namespace, &item.ident, cxx_name, rust_name);
271 let repr_ident = Ident::new(repr.as_ref(), Span::call_site());
272 let repr_type = Type::Ident(NamedType::new(repr_ident));
273 let repr = EnumRepr {
274 atom: repr,
275 repr_type,
276 };
277 let generics = Lifetimes {
278 lt_token: None,
279 lifetimes: Punctuated::new(),
280 gt_token: None,
281 };
282
283 Api::Enum(Enum {
284 cfg,
285 doc,
286 derives,
287 attrs,
288 visibility,
289 enum_token,
290 name,
291 generics,
292 brace_token,
293 variants,
294 repr,
295 explicit_repr,
296 })
297}
298
299fn parse_variant(
300 cx: &mut Errors,
301 mut variant: RustVariant,
302 discriminants: &mut DiscriminantSet,
303) -> Result<Variant> {
304 let mut cfg = CfgExpr::Unconditional;
305 let mut doc = Doc::new();
306 let mut default = false;
307 let mut cxx_name = None;
308 let mut rust_name = None;
309 let attrs = attrs::parse(
310 cx,
311 mem::take(&mut variant.attrs),
312 attrs::Parser {
313 cfg: Some(&mut cfg),
314 doc: Some(&mut doc),
315 default: Some(&mut default),
316 cxx_name: Some(&mut cxx_name),
317 rust_name: Some(&mut rust_name),
318 ..Default::default()
319 },
320 );
321
322 match variant.fields {
323 Fields::Unit => {}
324 _ => {
325 let msg = "enums with data are not supported yet";
326 return Err(Error::new_spanned(variant, msg));
327 }
328 }
329
330 let expr = variant.discriminant.as_ref().map(|(_, expr)| expr);
331 let try_discriminant = match &expr {
332 Some(lit) => discriminants.insert(lit),
333 None => discriminants.insert_next(),
334 };
335 let discriminant = match try_discriminant {
336 Ok(discriminant) => discriminant,
337 Err(err) => return Err(Error::new_spanned(variant, err)),
338 };
339
340 let name = pair(Namespace::ROOT, &variant.ident, cxx_name, rust_name);
341 let expr = variant.discriminant.map(|(_, expr)| expr);
342
343 Ok(Variant {
344 cfg,
345 doc,
346 default,
347 attrs,
348 name,
349 discriminant,
350 expr,
351 })
352}
353
354fn parse_foreign_mod(
355 cx: &mut Errors,
356 foreign_mod: ItemForeignMod,
357 out: &mut Vec<Api>,
358 trusted: bool,
359 namespace: &Namespace,
360) {
361 let lang = match parse_lang(&foreign_mod.abi) {
362 Ok(lang) => lang,
363 Err(err) => return cx.push(err),
364 };
365
366 match lang {
367 Lang::Rust => {
368 if foreign_mod.unsafety.is_some() {
369 let unsafety = foreign_mod.unsafety;
370 let abi = &foreign_mod.abi;
371 let span = quote!(#unsafety #abi);
372 cx.error(span, "extern \"Rust\" block does not need to be unsafe");
373 }
374 }
375 Lang::Cxx | Lang::CxxUnwind => {}
376 }
377
378 let trusted = trusted || foreign_mod.unsafety.is_some();
379
380 let mut cfg = CfgExpr::Unconditional;
381 let mut namespace = namespace.clone();
382 let attrs = attrs::parse(
383 cx,
384 foreign_mod.attrs,
385 attrs::Parser {
386 cfg: Some(&mut cfg),
387 namespace: Some(&mut namespace),
388 ..Default::default()
389 },
390 );
391
392 let mut items = Vec::new();
393 for foreign in foreign_mod.items {
394 match foreign {
395 ForeignItem::Type(foreign) => {
396 let ety = parse_extern_type(cx, foreign, lang, trusted, &cfg, &namespace, &attrs);
397 items.push(ety);
398 }
399 ForeignItem::Fn(foreign) => {
400 match parse_extern_fn(cx, foreign, lang, trusted, &cfg, &namespace, &attrs) {
401 Ok(efn) => items.push(efn),
402 Err(err) => cx.push(err),
403 }
404 }
405 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
406 match foreign.mac.parse_body_with(parse_include) {
407 Ok(mut include) => {
408 include.cfg = cfg.clone();
409 items.push(Api::Include(include));
410 }
411 Err(err) => cx.push(err),
412 }
413 }
414 ForeignItem::Verbatim(tokens) => {
415 match parse_extern_verbatim(cx, tokens, lang, trusted, &cfg, &namespace, &attrs) {
416 Ok(api) => items.push(api),
417 Err(err) => cx.push(err),
418 }
419 }
420 _ => cx.error(foreign, "unsupported foreign item"),
421 }
422 }
423
424 if !trusted
425 && items.iter().any(|api| match api {
426 Api::CxxFunction(efn) => efn.unsafety.is_none(),
427 _ => false,
428 })
429 {
430 cx.error(
431 foreign_mod.abi,
432 "block must be declared `unsafe extern \"C++\"` if it contains any safe-to-call C++ functions",
433 );
434 }
435
436 let mut types = items.iter().filter_map(|item| match item {
437 Api::CxxType(ety) | Api::RustType(ety) => Some(&ety.name),
438 Api::TypeAlias(alias) => Some(&alias.name),
439 _ => None,
440 });
441 if let (Some(single_type), None) = (types.next(), types.next()) {
442 let single_type = single_type.clone();
443 for item in &mut items {
444 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
445 if let Some(receiver) = efn.sig.receiver_mut() {
446 if receiver.ty.rust == "Self" {
447 receiver.ty.rust = single_type.rust.clone();
448 }
449 }
450 }
451 }
452 }
453
454 out.extend(items);
455}
456
457fn parse_lang(abi: &Abi) -> Result<Lang> {
458 let Some(name) = &abi.name else {
459 return Err(Error::new_spanned(
460 abi,
461 "ABI name is required, extern \"C++\" or extern \"Rust\"",
462 ));
463 };
464
465 match name.value().as_str() {
466 "C++" => Ok(Lang::Cxx),
467 "C++-unwind" => Ok(Lang::CxxUnwind),
468 "Rust" => Ok(Lang::Rust),
469 _ => Err(Error::new_spanned(
470 abi,
471 "unrecognized ABI, requires either \"C++\" or \"Rust\"",
472 )),
473 }
474}
475
476fn parse_extern_type(
477 cx: &mut Errors,
478 foreign_type: ForeignItemType,
479 lang: Lang,
480 trusted: bool,
481 extern_block_cfg: &CfgExpr,
482 namespace: &Namespace,
483 attrs: &OtherAttrs,
484) -> Api {
485 let mut cfg = extern_block_cfg.clone();
486 let mut doc = Doc::new();
487 let mut derives = Vec::new();
488 let mut namespace = namespace.clone();
489 let mut cxx_name = None;
490 let mut rust_name = None;
491 let mut attrs = attrs.clone();
492 attrs.extend(attrs::parse(
493 cx,
494 foreign_type.attrs,
495 attrs::Parser {
496 cfg: Some(&mut cfg),
497 doc: Some(&mut doc),
498 derives: Some(&mut derives),
499 namespace: Some(&mut namespace),
500 cxx_name: Some(&mut cxx_name),
501 rust_name: Some(&mut rust_name),
502 ..Default::default()
503 },
504 ));
505
506 let type_token = foreign_type.type_token;
507 let visibility = visibility_pub(&foreign_type.vis, type_token.span);
508 let name = pair(namespace, &foreign_type.ident, cxx_name, rust_name);
509 let generics = extern_type_lifetimes(cx, foreign_type.generics);
510 let colon_token = None;
511 let bounds = Vec::new();
512 let semi_token = foreign_type.semi_token;
513
514 (match lang {
515 Lang::Cxx | Lang::CxxUnwind => Api::CxxType,
516 Lang::Rust => Api::RustType,
517 })(ExternType {
518 cfg,
519 lang,
520 doc,
521 derives,
522 attrs,
523 visibility,
524 type_token,
525 name,
526 generics,
527 colon_token,
528 bounds,
529 semi_token,
530 trusted,
531 })
532}
533
534fn parse_extern_fn(
535 cx: &mut Errors,
536 mut foreign_fn: ForeignItemFn,
537 lang: Lang,
538 trusted: bool,
539 extern_block_cfg: &CfgExpr,
540 namespace: &Namespace,
541 attrs: &OtherAttrs,
542) -> Result<Api> {
543 let mut cfg = extern_block_cfg.clone();
544 let mut doc = Doc::new();
545 let mut namespace = namespace.clone();
546 let mut cxx_name = None;
547 let mut rust_name = None;
548 let mut self_type = None;
549 let mut attrs = attrs.clone();
550 attrs.extend(attrs::parse(
551 cx,
552 mem::take(&mut foreign_fn.attrs),
553 attrs::Parser {
554 cfg: Some(&mut cfg),
555 doc: Some(&mut doc),
556 namespace: Some(&mut namespace),
557 cxx_name: Some(&mut cxx_name),
558 rust_name: Some(&mut rust_name),
559 self_type: Some(&mut self_type),
560 ..Default::default()
561 },
562 ));
563
564 let generics = &foreign_fn.sig.generics;
565 if generics.where_clause.is_some()
566 || generics.params.iter().any(|param| match param {
567 GenericParam::Lifetime(lifetime) => !lifetime.bounds.is_empty(),
568 GenericParam::Type(_) | GenericParam::Const(_) => true,
569 })
570 {
571 return Err(Error::new_spanned(
572 foreign_fn,
573 "extern function with generic parameters is not supported yet",
574 ));
575 }
576
577 if let Some(variadic) = &foreign_fn.sig.variadic {
578 return Err(Error::new_spanned(
579 variadic,
580 "variadic function is not supported yet",
581 ));
582 }
583
584 if foreign_fn.sig.asyncness.is_some() {
585 return Err(Error::new_spanned(
586 foreign_fn,
587 "async function is not directly supported yet, but see https://cxx.rs/async.html \
588 for a working approach, and https://github.com/pcwalton/cxx-async for some helpers; \
589 eventually what you wrote will work but it isn't integrated into the cxx::bridge \
590 macro yet",
591 ));
592 }
593
594 if foreign_fn.sig.constness.is_some() {
595 return Err(Error::new_spanned(
596 foreign_fn,
597 "const extern function is not supported",
598 ));
599 }
600
601 if let Some(abi) = &foreign_fn.sig.abi {
602 return Err(Error::new_spanned(
603 abi,
604 "explicit ABI on extern function is not supported",
605 ));
606 }
607
608 let mut receiver = None;
609 let mut args = Punctuated::new();
610 for arg in foreign_fn.sig.inputs.pairs() {
611 let (arg, comma) = arg.into_tuple();
612 match arg {
613 FnArg::Receiver(arg) => {
614 if let Some((ampersand, lifetime)) = &arg.reference {
615 receiver = Some(Receiver {
616 pinned: false,
617 ampersand: *ampersand,
618 lifetime: lifetime.clone(),
619 mutable: arg.mutability.is_some(),
620 var: arg.self_token,
621 colon_token: Token,
622 ty: NamedType::new(Ident::new("Self", arg.self_token.span)),
623 shorthand: true,
624 pin_tokens: None,
625 mutability: arg.mutability,
626 });
627 continue;
628 }
629 if let Some(colon_token) = arg.colon_token {
630 let ty = parse_type(&arg.ty)?;
631 if let Type::Ref(reference) = ty {
632 if let Type::Ident(ident) = reference.inner {
633 receiver = Some(Receiver {
634 pinned: reference.pinned,
635 ampersand: reference.ampersand,
636 lifetime: reference.lifetime,
637 mutable: reference.mutable,
638 var: Token),
639 colon_token,
640 ty: ident,
641 shorthand: false,
642 pin_tokens: reference.pin_tokens,
643 mutability: reference.mutability,
644 });
645 continue;
646 }
647 }
648 }
649 return Err(Error::new_spanned(arg, "unsupported method receiver"));
650 }
651 FnArg::Typed(arg) => {
652 let ident = match arg.pat.as_ref() {
653 Pat::Ident(pat) => pat.ident.clone(),
654 Pat::Wild(pat) => {
655 Ident::new(&format!("arg{}", args.len()), pat.underscore_token.span)
656 }
657 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
658 };
659 let ty = parse_type(&arg.ty)?;
660 let cfg = CfgExpr::Unconditional;
661 let doc = Doc::new();
662 let attrs = OtherAttrs::new();
663 let visibility = Token);
664 let name = pair(Namespace::default(), &ident, None, None);
665 let colon_token = arg.colon_token;
666 args.push_value(Var {
667 cfg,
668 doc,
669 attrs,
670 visibility,
671 name,
672 colon_token,
673 ty,
674 });
675 if let Some(comma) = comma {
676 args.push_punct(*comma);
677 }
678 }
679 }
680 }
681
682 let kind = match (self_type, receiver) {
683 (None, None) => FnKind::Free,
684 (Some(self_type), None) => FnKind::Assoc(self_type),
685 (None, Some(receiver)) => FnKind::Method(receiver),
686 (Some(self_type), Some(receiver)) => {
687 let msg = "function with Self type must not have a `self` argument";
688 cx.error(self_type, msg);
689 FnKind::Method(receiver)
690 }
691 };
692
693 let mut throws_tokens = None;
694 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
695 let throws = throws_tokens.is_some();
696 let asyncness = foreign_fn.sig.asyncness;
697 let unsafety = foreign_fn.sig.unsafety;
698 let fn_token = foreign_fn.sig.fn_token;
699 let inherited_span = unsafety.map_or(fn_token.span, |unsafety| unsafety.span);
700 let visibility = visibility_pub(&foreign_fn.vis, inherited_span);
701 let name = pair(namespace, &foreign_fn.sig.ident, cxx_name, rust_name);
702 let generics = generics.clone();
703 let paren_token = foreign_fn.sig.paren_token;
704 let semi_token = foreign_fn.semi_token;
705
706 Ok(match lang {
707 Lang::Cxx | Lang::CxxUnwind => Api::CxxFunction,
708 Lang::Rust => Api::RustFunction,
709 }(ExternFn {
710 cfg,
711 lang,
712 doc,
713 attrs,
714 visibility,
715 name,
716 sig: Signature {
717 asyncness,
718 unsafety,
719 fn_token,
720 generics,
721 kind,
722 args,
723 ret,
724 throws,
725 paren_token,
726 throws_tokens,
727 },
728 semi_token,
729 trusted,
730 }))
731}
732
733fn parse_extern_verbatim(
734 cx: &mut Errors,
735 tokens: TokenStream,
736 lang: Lang,
737 trusted: bool,
738 extern_block_cfg: &CfgExpr,
739 namespace: &Namespace,
740 attrs: &OtherAttrs,
741) -> Result<Api> {
742 |input: ParseStream| -> Result<Api> {
743 let unparsed_attrs = input.call(Attribute::parse_outer)?;
744 let visibility: Visibility = input.parse()?;
745 if input.peek(Token![type]) {
746 parse_extern_verbatim_type(
747 cx,
748 unparsed_attrs,
749 visibility,
750 input,
751 lang,
752 trusted,
753 extern_block_cfg,
754 namespace,
755 attrs,
756 )
757 } else if input.peek(Token![fn]) {
758 parse_extern_verbatim_fn(input)
759 } else {
760 let span = input.cursor().token_stream();
761 Err(Error::new_spanned(
762 span,
763 "unsupported foreign item, expected `type` or `fn`",
764 ))
765 }
766 }
767 .parse2(tokens)
768}
769
770fn parse_extern_verbatim_type(
771 cx: &mut Errors,
772 unparsed_attrs: Vec<Attribute>,
773 visibility: Visibility,
774 input: ParseStream,
775 lang: Lang,
776 trusted: bool,
777 extern_block_cfg: &CfgExpr,
778 namespace: &Namespace,
779 attrs: &OtherAttrs,
780) -> Result<Api> {
781 let type_token: Token![type] = input.parse()?;
782 let ident: Ident = input.parse()?;
783 let generics: Generics = input.parse()?;
784 let lifetimes = extern_type_lifetimes(cx, generics);
785 let lookahead = input.lookahead1();
786 if lookahead.peek(Token![=]) {
787 parse_type_alias(
789 cx,
790 unparsed_attrs,
791 visibility,
792 type_token,
793 ident,
794 lifetimes,
795 input,
796 lang,
797 extern_block_cfg,
798 namespace,
799 attrs,
800 )
801 } else if lookahead.peek(Token![:]) {
802 parse_extern_type_bounded(
804 cx,
805 unparsed_attrs,
806 visibility,
807 type_token,
808 ident,
809 lifetimes,
810 input,
811 lang,
812 trusted,
813 extern_block_cfg,
814 namespace,
815 attrs,
816 )
817 } else {
818 Err(lookahead.error())
819 }
820}
821
822fn extern_type_lifetimes(cx: &mut Errors, generics: Generics) -> Lifetimes {
823 let mut lifetimes = Punctuated::new();
824 let mut has_unsupported_generic_param = false;
825 for pair in generics.params.into_pairs() {
826 let (param, punct) = pair.into_tuple();
827 match param {
828 GenericParam::Lifetime(param) => {
829 if !param.bounds.is_empty() && !has_unsupported_generic_param {
830 let msg = "lifetime parameter with bounds is not supported yet";
831 cx.error(¶m, msg);
832 has_unsupported_generic_param = true;
833 }
834 lifetimes.push_value(param.lifetime);
835 if let Some(punct) = punct {
836 lifetimes.push_punct(punct);
837 }
838 }
839 GenericParam::Type(param) => {
840 if !has_unsupported_generic_param {
841 let msg = "extern type with generic type parameter is not supported yet";
842 cx.error(¶m, msg);
843 has_unsupported_generic_param = true;
844 }
845 }
846 GenericParam::Const(param) => {
847 if !has_unsupported_generic_param {
848 let msg = "extern type with const generic parameter is not supported yet";
849 cx.error(¶m, msg);
850 has_unsupported_generic_param = true;
851 }
852 }
853 }
854 }
855 Lifetimes {
856 lt_token: generics.lt_token,
857 lifetimes,
858 gt_token: generics.gt_token,
859 }
860}
861
862fn parse_extern_verbatim_fn(input: ParseStream) -> Result<Api> {
863 input.parse::<RustSignature>()?;
864 input.parse::<Token![;]>()?;
865 unreachable!()
866}
867
868fn parse_type_alias(
869 cx: &mut Errors,
870 unparsed_attrs: Vec<Attribute>,
871 visibility: Visibility,
872 type_token: Token![type],
873 ident: Ident,
874 generics: Lifetimes,
875 input: ParseStream,
876 lang: Lang,
877 extern_block_cfg: &CfgExpr,
878 namespace: &Namespace,
879 attrs: &OtherAttrs,
880) -> Result<Api> {
881 let eq_token: Token![=] = input.parse()?;
882 let ty: RustType = input.parse()?;
883 let semi_token: Token![;] = input.parse()?;
884
885 let mut cfg = extern_block_cfg.clone();
886 let mut doc = Doc::new();
887 let mut derives = Vec::new();
888 let mut namespace = namespace.clone();
889 let mut cxx_name = None;
890 let mut rust_name = None;
891 let mut attrs = attrs.clone();
892 attrs.extend(attrs::parse(
893 cx,
894 unparsed_attrs,
895 attrs::Parser {
896 cfg: Some(&mut cfg),
897 doc: Some(&mut doc),
898 derives: Some(&mut derives),
899 namespace: Some(&mut namespace),
900 cxx_name: Some(&mut cxx_name),
901 rust_name: Some(&mut rust_name),
902 ..Default::default()
903 },
904 ));
905
906 if lang == Lang::Rust {
907 let span = quote!(#type_token #semi_token);
908 let msg = "type alias in extern \"Rust\" block is not supported";
909 return Err(Error::new_spanned(span, msg));
910 }
911
912 let visibility = visibility_pub(&visibility, type_token.span);
913 let name = pair(namespace, &ident, cxx_name, rust_name);
914
915 Ok(Api::TypeAlias(TypeAlias {
916 cfg,
917 doc,
918 derives,
919 attrs,
920 visibility,
921 type_token,
922 name,
923 generics,
924 eq_token,
925 ty,
926 semi_token,
927 }))
928}
929
930fn parse_extern_type_bounded(
931 cx: &mut Errors,
932 unparsed_attrs: Vec<Attribute>,
933 visibility: Visibility,
934 type_token: Token![type],
935 ident: Ident,
936 generics: Lifetimes,
937 input: ParseStream,
938 lang: Lang,
939 trusted: bool,
940 extern_block_cfg: &CfgExpr,
941 namespace: &Namespace,
942 attrs: &OtherAttrs,
943) -> Result<Api> {
944 let mut bounds = Vec::new();
945 let colon_token: Option<Token![:]> = input.parse()?;
946 if colon_token.is_some() {
947 loop {
948 match input.parse()? {
949 TypeParamBound::Trait(TraitBound {
950 paren_token: None,
951 modifier: TraitBoundModifier::None,
952 lifetimes: None,
953 path,
954 }) if if let Some(derive) = path.get_ident().and_then(Derive::from) {
955 bounds.push(derive);
956 true
957 } else {
958 false
959 } => {}
960 bound => cx.error(bound, "unsupported trait"),
961 }
962
963 let lookahead = input.lookahead1();
964 if lookahead.peek(Token![+]) {
965 input.parse::<Token![+]>()?;
966 } else if lookahead.peek(Token![;]) {
967 break;
968 } else {
969 return Err(lookahead.error());
970 }
971 }
972 }
973 let semi_token: Token![;] = input.parse()?;
974
975 let mut cfg = extern_block_cfg.clone();
976 let mut doc = Doc::new();
977 let mut derives = Vec::new();
978 let mut namespace = namespace.clone();
979 let mut cxx_name = None;
980 let mut rust_name = None;
981 let mut attrs = attrs.clone();
982 attrs.extend(attrs::parse(
983 cx,
984 unparsed_attrs,
985 attrs::Parser {
986 cfg: Some(&mut cfg),
987 doc: Some(&mut doc),
988 derives: Some(&mut derives),
989 namespace: Some(&mut namespace),
990 cxx_name: Some(&mut cxx_name),
991 rust_name: Some(&mut rust_name),
992 ..Default::default()
993 },
994 ));
995
996 let visibility = visibility_pub(&visibility, type_token.span);
997 let name = pair(namespace, &ident, cxx_name, rust_name);
998
999 Ok(match lang {
1000 Lang::Cxx | Lang::CxxUnwind => Api::CxxType,
1001 Lang::Rust => Api::RustType,
1002 }(ExternType {
1003 cfg,
1004 lang,
1005 doc,
1006 derives,
1007 attrs,
1008 visibility,
1009 type_token,
1010 name,
1011 generics,
1012 colon_token,
1013 bounds,
1014 semi_token,
1015 trusted,
1016 }))
1017}
1018
1019fn parse_impl(cx: &mut Errors, imp: ItemImpl) -> Result<Api> {
1020 let impl_token = imp.impl_token;
1021
1022 let mut cfg = CfgExpr::Unconditional;
1023 let attrs = attrs::parse(
1024 cx,
1025 imp.attrs,
1026 attrs::Parser {
1027 cfg: Some(&mut cfg),
1028 ..Default::default()
1029 },
1030 );
1031
1032 if !imp.items.is_empty() {
1033 let mut span = Group::new(Delimiter::Brace, TokenStream::new());
1034 span.set_span(imp.brace_token.span.join());
1035 return Err(Error::new_spanned(span, "expected an empty impl block"));
1036 }
1037
1038 if let Some((bang, path, for_token)) = &imp.trait_ {
1039 let self_ty = &imp.self_ty;
1040 let span = quote!(#bang #path #for_token #self_ty);
1041 return Err(Error::new_spanned(
1042 span,
1043 "unexpected impl, expected something like `impl UniquePtr<T> {}`",
1044 ));
1045 }
1046
1047 if let Some(where_clause) = imp.generics.where_clause {
1048 return Err(Error::new_spanned(
1049 where_clause,
1050 "where-clause on an impl is not supported yet",
1051 ));
1052 }
1053 let mut impl_generics = Lifetimes {
1054 lt_token: imp.generics.lt_token,
1055 lifetimes: Punctuated::new(),
1056 gt_token: imp.generics.gt_token,
1057 };
1058 for pair in imp.generics.params.into_pairs() {
1059 let (param, punct) = pair.into_tuple();
1060 match param {
1061 GenericParam::Lifetime(def) if def.bounds.is_empty() => {
1062 impl_generics.lifetimes.push_value(def.lifetime);
1063 if let Some(punct) = punct {
1064 impl_generics.lifetimes.push_punct(punct);
1065 }
1066 }
1067 _ => {
1068 let span = quote!(#impl_token #impl_generics);
1069 return Err(Error::new_spanned(
1070 span,
1071 "generic parameter on an impl is not supported yet",
1072 ));
1073 }
1074 }
1075 }
1076
1077 let mut negative_token = None;
1078 let mut self_ty = *imp.self_ty;
1079 if let RustType::Verbatim(ty) = &self_ty {
1080 let mut iter = ty.clone().into_iter();
1081 if let Some(TokenTree::Punct(punct)) = iter.next() {
1082 if punct.as_char() == '!' {
1083 let ty = iter.collect::<TokenStream>();
1084 if !ty.is_empty() {
1085 negative_token = Some(Token));
1086 self_ty = syn::parse2(ty)?;
1087 }
1088 }
1089 }
1090 }
1091
1092 let ty = parse_type(&self_ty)?;
1093 let ty_generics = match &ty {
1094 Type::RustBox(ty)
1095 | Type::RustVec(ty)
1096 | Type::UniquePtr(ty)
1097 | Type::SharedPtr(ty)
1098 | Type::WeakPtr(ty)
1099 | Type::CxxVector(ty) => match &ty.inner {
1100 Type::Ident(ident) => ident.generics.clone(),
1101 _ => Lifetimes::default(),
1102 },
1103 Type::Ident(_)
1104 | Type::Ref(_)
1105 | Type::Ptr(_)
1106 | Type::Str(_)
1107 | Type::Fn(_)
1108 | Type::Void(_)
1109 | Type::SliceRef(_)
1110 | Type::Array(_) => Lifetimes::default(),
1111 };
1112
1113 let negative = negative_token.is_some();
1114 let brace_token = imp.brace_token;
1115
1116 Ok(Api::Impl(Impl {
1117 cfg,
1118 attrs,
1119 impl_token,
1120 impl_generics,
1121 negative,
1122 ty,
1123 ty_generics,
1124 brace_token,
1125 negative_token,
1126 }))
1127}
1128
1129fn parse_include(input: ParseStream) -> Result<Include> {
1130 if input.peek(LitStr) {
1131 let lit: LitStr = input.parse()?;
1132 let span = lit.span();
1133 return Ok(Include {
1134 cfg: CfgExpr::Unconditional,
1135 path: lit.value(),
1136 kind: IncludeKind::Quoted,
1137 begin_span: span,
1138 end_span: span,
1139 });
1140 }
1141
1142 if input.peek(Token![<]) {
1143 let mut path = String::new();
1144
1145 let langle: Token![<] = input.parse()?;
1146 while !input.is_empty() && !input.peek(Token![>]) {
1147 let token: TokenTree = input.parse()?;
1148 match token {
1149 TokenTree::Ident(token) => path += &token.to_string(),
1150 TokenTree::Literal(token)
1151 if token
1152 .to_string()
1153 .starts_with(|ch: char| ch.is_ascii_digit()) =>
1154 {
1155 path += &token.to_string();
1156 }
1157 TokenTree::Punct(token) => path.push(token.as_char()),
1158 _ => return Err(Error::new(token.span(), "unexpected token in include path")),
1159 }
1160 }
1161 let rangle: Token![>] = input.parse()?;
1162
1163 return Ok(Include {
1164 cfg: CfgExpr::Unconditional,
1165 path,
1166 kind: IncludeKind::Bracketed,
1167 begin_span: langle.span,
1168 end_span: rangle.span,
1169 });
1170 }
1171
1172 Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))
1173}
1174
1175fn parse_type(ty: &RustType) -> Result<Type> {
1176 match ty {
1177 RustType::Reference(ty) => parse_type_reference(ty),
1178 RustType::Ptr(ty) => parse_type_ptr(ty),
1179 RustType::Path(ty) => parse_type_path(ty),
1180 RustType::Array(ty) => parse_type_array(ty),
1181 RustType::BareFn(ty) => parse_type_fn(ty),
1182 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span.join())),
1183 _ => Err(Error::new_spanned(ty, "unsupported type")),
1184 }
1185}
1186
1187fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
1188 let ampersand = ty.and_token;
1189 let lifetime = ty.lifetime.clone();
1190 let mutable = ty.mutability.is_some();
1191 let mutability = ty.mutability;
1192
1193 if let RustType::Slice(slice) = ty.elem.as_ref() {
1194 let inner = parse_type(&slice.elem)?;
1195 let bracket = slice.bracket_token;
1196 return Ok(Type::SliceRef(Box::new(SliceRef {
1197 ampersand,
1198 lifetime,
1199 mutable,
1200 bracket,
1201 inner,
1202 mutability,
1203 })));
1204 }
1205
1206 let inner = parse_type(&ty.elem)?;
1207 let pinned = false;
1208 let pin_tokens = None;
1209
1210 Ok(match &inner {
1211 Type::Ident(ident) if ident.rust == "str" => {
1212 if ty.mutability.is_some() {
1213 return Err(Error::new_spanned(ty, "unsupported type"));
1214 } else {
1215 Type::Str
1216 }
1217 }
1218 _ => Type::Ref,
1219 }(Box::new(Ref {
1220 pinned,
1221 ampersand,
1222 lifetime,
1223 mutable,
1224 inner,
1225 pin_tokens,
1226 mutability,
1227 })))
1228}
1229
1230fn parse_type_ptr(ty: &TypePtr) -> Result<Type> {
1231 let star = ty.star_token;
1232 let mutable = ty.mutability.is_some();
1233 let constness = ty.const_token;
1234 let mutability = ty.mutability;
1235
1236 let inner = parse_type(&ty.elem)?;
1237
1238 Ok(Type::Ptr(Box::new(Ptr {
1239 star,
1240 mutable,
1241 inner,
1242 mutability,
1243 constness,
1244 })))
1245}
1246
1247fn parse_type_path(ty: &TypePath) -> Result<Type> {
1248 let path = &ty.path;
1249 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
1250 let segment = &path.segments[0];
1251 let ident = segment.ident.clone();
1252 match &segment.arguments {
1253 PathArguments::None => return Ok(Type::Ident(NamedType::new(ident))),
1254 PathArguments::AngleBracketed(generic) => {
1255 if ident == "UniquePtr" && generic.args.len() == 1 {
1256 if let GenericArgument::Type(arg) = &generic.args[0] {
1257 let inner = parse_type(arg)?;
1258 return Ok(Type::UniquePtr(Box::new(Ty1 {
1259 name: ident,
1260 langle: generic.lt_token,
1261 inner,
1262 rangle: generic.gt_token,
1263 })));
1264 }
1265 } else if ident == "SharedPtr" && generic.args.len() == 1 {
1266 if let GenericArgument::Type(arg) = &generic.args[0] {
1267 let inner = parse_type(arg)?;
1268 return Ok(Type::SharedPtr(Box::new(Ty1 {
1269 name: ident,
1270 langle: generic.lt_token,
1271 inner,
1272 rangle: generic.gt_token,
1273 })));
1274 }
1275 } else if ident == "WeakPtr" && generic.args.len() == 1 {
1276 if let GenericArgument::Type(arg) = &generic.args[0] {
1277 let inner = parse_type(arg)?;
1278 return Ok(Type::WeakPtr(Box::new(Ty1 {
1279 name: ident,
1280 langle: generic.lt_token,
1281 inner,
1282 rangle: generic.gt_token,
1283 })));
1284 }
1285 } else if ident == "CxxVector" && generic.args.len() == 1 {
1286 if let GenericArgument::Type(arg) = &generic.args[0] {
1287 let inner = parse_type(arg)?;
1288 return Ok(Type::CxxVector(Box::new(Ty1 {
1289 name: ident,
1290 langle: generic.lt_token,
1291 inner,
1292 rangle: generic.gt_token,
1293 })));
1294 }
1295 } else if ident == "Box" && generic.args.len() == 1 {
1296 if let GenericArgument::Type(arg) = &generic.args[0] {
1297 let inner = parse_type(arg)?;
1298 return Ok(Type::RustBox(Box::new(Ty1 {
1299 name: ident,
1300 langle: generic.lt_token,
1301 inner,
1302 rangle: generic.gt_token,
1303 })));
1304 }
1305 } else if ident == "Vec" && generic.args.len() == 1 {
1306 if let GenericArgument::Type(arg) = &generic.args[0] {
1307 let inner = parse_type(arg)?;
1308 return Ok(Type::RustVec(Box::new(Ty1 {
1309 name: ident,
1310 langle: generic.lt_token,
1311 inner,
1312 rangle: generic.gt_token,
1313 })));
1314 }
1315 } else if ident == "Pin" && generic.args.len() == 1 {
1316 if let GenericArgument::Type(arg) = &generic.args[0] {
1317 let inner = parse_type(arg)?;
1318 let pin_token = kw::Pin(ident.span());
1319 if let Type::Ref(mut inner) = inner {
1320 inner.pinned = true;
1321 inner.pin_tokens =
1322 Some((pin_token, generic.lt_token, generic.gt_token));
1323 return Ok(Type::Ref(inner));
1324 }
1325 }
1326 } else {
1327 let mut lifetimes = Punctuated::new();
1328 let mut only_lifetimes = true;
1329 for pair in generic.args.pairs() {
1330 let (param, punct) = pair.into_tuple();
1331 if let GenericArgument::Lifetime(param) = param {
1332 lifetimes.push_value(param.clone());
1333 if let Some(punct) = punct {
1334 lifetimes.push_punct(*punct);
1335 }
1336 } else {
1337 only_lifetimes = false;
1338 break;
1339 }
1340 }
1341 if only_lifetimes {
1342 return Ok(Type::Ident(NamedType {
1343 rust: ident,
1344 generics: Lifetimes {
1345 lt_token: Some(generic.lt_token),
1346 lifetimes,
1347 gt_token: Some(generic.gt_token),
1348 },
1349 }));
1350 }
1351 }
1352 }
1353 PathArguments::Parenthesized(_) => {}
1354 }
1355 }
1356
1357 if ty.qself.is_none() && path.segments.len() == 2 && path.segments[0].ident == "cxx" {
1358 return Err(Error::new_spanned(
1359 ty,
1360 "unexpected `cxx::` qualifier found in a `#[cxx::bridge]`",
1361 ));
1362 }
1363
1364 Err(Error::new_spanned(ty, "unsupported type"))
1365}
1366
1367fn parse_type_array(ty: &TypeArray) -> Result<Type> {
1368 let inner = parse_type(&ty.elem)?;
1369
1370 let Expr::Lit(len_expr) = &ty.len else {
1371 let msg = "unsupported expression, array length must be an integer literal";
1372 return Err(Error::new_spanned(&ty.len, msg));
1373 };
1374
1375 let Lit::Int(len_token) = &len_expr.lit else {
1376 let msg = "array length must be an integer literal";
1377 return Err(Error::new_spanned(len_expr, msg));
1378 };
1379
1380 let len = len_token.base10_parse::<usize>()?;
1381 if len == 0 {
1382 let msg = "array with zero size is not supported";
1383 return Err(Error::new_spanned(ty, msg));
1384 }
1385
1386 let bracket = ty.bracket_token;
1387 let semi_token = ty.semi_token;
1388
1389 Ok(Type::Array(Box::new(Array {
1390 bracket,
1391 inner,
1392 semi_token,
1393 len,
1394 len_token: len_token.clone(),
1395 })))
1396}
1397
1398fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
1399 if ty.lifetimes.is_some() {
1400 return Err(Error::new_spanned(
1401 ty,
1402 "function pointer with lifetime parameters is not supported yet",
1403 ));
1404 }
1405
1406 if ty.variadic.is_some() {
1407 return Err(Error::new_spanned(
1408 ty,
1409 "variadic function pointer is not supported yet",
1410 ));
1411 }
1412
1413 let args = ty
1414 .inputs
1415 .iter()
1416 .enumerate()
1417 .map(|(i, arg)| {
1418 let (ident, colon_token) = match &arg.name {
1419 Some((ident, colon_token)) => (ident.clone(), *colon_token),
1420 None => {
1421 let fn_span = ty.paren_token.span.join();
1422 let ident = format_ident!("arg{}", i, span = fn_span);
1423 let colon_token = Token;
1424 (ident, colon_token)
1425 }
1426 };
1427 let ty = parse_type(&arg.ty)?;
1428 let cfg = CfgExpr::Unconditional;
1429 let doc = Doc::new();
1430 let attrs = OtherAttrs::new();
1431 let visibility = Token);
1432 let name = pair(Namespace::default(), &ident, None, None);
1433 Ok(Var {
1434 cfg,
1435 doc,
1436 attrs,
1437 visibility,
1438 name,
1439 colon_token,
1440 ty,
1441 })
1442 })
1443 .collect::<Result<_>>()?;
1444
1445 let mut throws_tokens = None;
1446 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
1447 let throws = throws_tokens.is_some();
1448
1449 let asyncness = None;
1450 let unsafety = ty.unsafety;
1451 let fn_token = ty.fn_token;
1452 let generics = Generics::default();
1453 let kind = FnKind::Free;
1454 let paren_token = ty.paren_token;
1455
1456 Ok(Type::Fn(Box::new(Signature {
1457 asyncness,
1458 unsafety,
1459 fn_token,
1460 generics,
1461 kind,
1462 args,
1463 ret,
1464 throws,
1465 paren_token,
1466 throws_tokens,
1467 })))
1468}
1469
1470fn parse_return_type(
1471 ty: &ReturnType,
1472 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
1473) -> Result<Option<Type>> {
1474 let mut ret = match ty {
1475 ReturnType::Default => return Ok(None),
1476 ReturnType::Type(_, ret) => ret.as_ref(),
1477 };
1478
1479 if let RustType::Path(ty) = ret {
1480 let path = &ty.path;
1481 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
1482 let segment = &path.segments[0];
1483 let ident = segment.ident.clone();
1484 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
1485 if ident == "Result" && generic.args.len() == 1 {
1486 if let GenericArgument::Type(arg) = &generic.args[0] {
1487 ret = arg;
1488 *throws_tokens =
1489 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
1490 }
1491 }
1492 }
1493 }
1494 }
1495
1496 match parse_type(ret)? {
1497 Type::Void(_) => Ok(None),
1498 ty => Ok(Some(ty)),
1499 }
1500}
1501
1502fn visibility_pub(vis: &Visibility, inherited: Span) -> Token![pub] {
1503 Token => vis.span,
1505 Visibility::Restricted(vis) => vis.pub_token.span,
1506 Visibility::Inherited => inherited,
1507 })
1508}
1509
1510fn pair(
1511 namespace: Namespace,
1512 default: &Ident,
1513 cxx: Option<ForeignName>,
1514 rust: Option<Ident>,
1515) -> Pair {
1516 Pair {
1517 namespace,
1518 cxx: cxx
1519 .unwrap_or_else(|| ForeignName::parse(&default.to_string(), default.span()).unwrap()),
1520 rust: rust.unwrap_or_else(|| default.clone()),
1521 }
1522}