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