Skip to main content

cxx_gen/syntax/
parse.rs

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