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