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