cxx_gen/syntax/
parse.rs

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