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