1 use proc_macro2::{Delimiter, Group, Span, TokenStream}; 2 use quote::{format_ident, quote, quote_spanned, ToTokens}; 3 use syn::{ 4 parse_quote, token, visit_mut::VisitMut, Attribute, Data, DataEnum, DeriveInput, Error, Field, 5 Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, Lifetime, LifetimeDef, Meta, 6 MetaList, MetaNameValue, NestedMeta, Result, Token, Type, Variant, Visibility, WhereClause, 7 }; 8 9 use super::{ 10 args::{parse_args, Args, ProjReplace, UnpinImpl}, 11 PIN, 12 }; 13 use crate::utils::{ 14 determine_lifetime_name, determine_visibility, insert_lifetime_and_bound, ReplaceReceiver, 15 SliceExt, Variants, 16 }; 17 18 pub(super) fn parse_derive(input: TokenStream) -> Result<TokenStream> { 19 let mut input: DeriveInput = syn::parse2(input)?; 20 21 let mut cx; 22 let mut generate = GenerateTokens::default(); 23 24 let ident = &input.ident; 25 let ty_generics = input.generics.split_for_impl().1; 26 let self_ty = parse_quote!(#ident #ty_generics); 27 let mut visitor = ReplaceReceiver(&self_ty); 28 visitor.visit_generics_mut(&mut input.generics); 29 visitor.visit_data_mut(&mut input.data); 30 31 match &input.data { 32 Data::Struct(data) => { 33 cx = Context::new(&input.attrs, &input.vis, ident, &mut input.generics, Struct)?; 34 parse_struct(&mut cx, &data.fields, &mut generate)?; 35 } 36 Data::Enum(data) => { 37 cx = Context::new(&input.attrs, &input.vis, ident, &mut input.generics, Enum)?; 38 parse_enum(&mut cx, data, &mut generate)?; 39 } 40 Data::Union(_) => { 41 return Err(error!( 42 input, 43 "#[pin_project] attribute may only be used on structs or enums" 44 )); 45 } 46 } 47 48 Ok(generate.into_tokens(&cx)) 49 } 50 51 #[derive(Default)] 52 struct GenerateTokens { 53 exposed: TokenStream, 54 scoped: TokenStream, 55 } 56 57 impl GenerateTokens { 58 fn extend(&mut self, expose: bool, tokens: TokenStream) { 59 if expose { 60 self.exposed.extend(tokens); 61 } else { 62 self.scoped.extend(tokens); 63 } 64 } 65 66 fn into_tokens(self, cx: &Context<'_>) -> TokenStream { 67 let mut tokens = self.exposed; 68 let scoped = self.scoped; 69 70 let unpin_impl = make_unpin_impl(cx); 71 let drop_impl = make_drop_impl(cx); 72 let allowed_lints = global_allowed_lints(); 73 74 tokens.extend(quote! { 75 // All items except projected types are generated inside a `const` scope. 76 // This makes it impossible for user code to refer to these types. 77 // However, this prevents Rustdoc from displaying docs for any 78 // of our types. In particular, users cannot see the 79 // automatically generated `Unpin` impl for the '__UnpinStruct' types 80 // 81 // Previously, we provided a flag to correctly document the 82 // automatically generated `Unpin` impl by using def-site hygiene, 83 // but it is now removed. 84 // 85 // Refs: 86 // * https://github.com/rust-lang/rust/issues/63281 87 // * https://github.com/taiki-e/pin-project/pull/53#issuecomment-525906867 88 // * https://github.com/taiki-e/pin-project/pull/70 89 #allowed_lints 90 #[allow(clippy::semicolon_if_nothing_returned)] 91 #[allow(clippy::use_self)] 92 #[allow(clippy::used_underscore_binding)] 93 const _: () = { 94 #scoped 95 #unpin_impl 96 #drop_impl 97 }; 98 }); 99 tokens 100 } 101 } 102 103 /// Returns attributes that should be applied to all generated code. 104 fn global_allowed_lints() -> TokenStream { 105 quote! { 106 #[allow(box_pointers)] // This lint warns use of the `Box` type. 107 #[allow(deprecated)] 108 #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993 109 #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 110 #[allow(unreachable_pub)] // This lint warns `pub` field in private struct. 111 // This lint warns of `clippy::*` generated by external macros. 112 // We allow this lint for compatibility with older compilers. 113 #[allow(clippy::unknown_clippy_lints)] 114 #[allow(clippy::pattern_type_mismatch)] 115 #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. 116 #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 117 } 118 } 119 120 /// Returns attributes used on projected types. 121 fn proj_allowed_lints(cx: &Context<'_>) -> (TokenStream, TokenStream, TokenStream) { 122 let large_enum_variant = if cx.kind == Enum { 123 Some(quote! { 124 #[allow(variant_size_differences)] 125 #[allow(clippy::large_enum_variant)] 126 }) 127 } else { 128 None 129 }; 130 let global_allowed_lints = global_allowed_lints(); 131 let proj_mut_allowed_lints = if cx.project { Some(&global_allowed_lints) } else { None }; 132 let proj_mut = quote! { 133 #proj_mut_allowed_lints 134 #[allow(dead_code)] // This lint warns unused fields/variants. 135 #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. 136 }; 137 let proj_ref_allowed_lints = if cx.project_ref { Some(&global_allowed_lints) } else { None }; 138 let proj_ref = quote! { 139 #proj_ref_allowed_lints 140 #[allow(dead_code)] // This lint warns unused fields/variants. 141 #[allow(clippy::ref_option_ref)] // This lint warns `&Option<&<ty>>`. 142 }; 143 let proj_own_allowed_lints = 144 if cx.project_replace.ident().is_some() { Some(&global_allowed_lints) } else { None }; 145 let proj_own = quote! { 146 #proj_own_allowed_lints 147 #[allow(dead_code)] // This lint warns unused fields/variants. 148 #large_enum_variant 149 }; 150 (proj_mut, proj_ref, proj_own) 151 } 152 153 struct Context<'a> { 154 /// The original type. 155 orig: OriginalType<'a>, 156 /// The projected types. 157 proj: ProjectedType, 158 /// Types of the pinned fields. 159 pinned_fields: Vec<&'a Type>, 160 /// Kind of the original type: struct or enum 161 kind: TypeKind, 162 163 /// `PinnedDrop` argument. 164 pinned_drop: Option<Span>, 165 /// `UnsafeUnpin` or `!Unpin` argument. 166 unpin_impl: UnpinImpl, 167 /// `project` argument. 168 project: bool, 169 /// `project_ref` argument. 170 project_ref: bool, 171 /// `project_replace [= <ident>]` argument. 172 project_replace: ProjReplace, 173 } 174 175 impl<'a> Context<'a> { 176 fn new( 177 attrs: &'a [Attribute], 178 vis: &'a Visibility, 179 ident: &'a Ident, 180 generics: &'a mut Generics, 181 kind: TypeKind, 182 ) -> Result<Self> { 183 let Args { pinned_drop, unpin_impl, project, project_ref, project_replace } = 184 parse_args(attrs)?; 185 186 if let Some(name) = [project.as_ref(), project_ref.as_ref(), project_replace.ident()] 187 .iter() 188 .filter_map(Option::as_ref) 189 .find(|name| **name == ident) 190 { 191 return Err(error!(name, "name `{}` is the same as the original type name", name)); 192 } 193 194 let mut lifetime_name = String::from("'pin"); 195 determine_lifetime_name(&mut lifetime_name, generics); 196 let lifetime = Lifetime::new(&lifetime_name, Span::call_site()); 197 198 let ty_generics = generics.split_for_impl().1; 199 let ty_generics_as_generics = parse_quote!(#ty_generics); 200 let mut proj_generics = generics.clone(); 201 let pred = insert_lifetime_and_bound( 202 &mut proj_generics, 203 lifetime.clone(), 204 &ty_generics_as_generics, 205 ident, 206 ); 207 let mut where_clause = generics.make_where_clause().clone(); 208 where_clause.predicates.push(pred); 209 210 let own_ident = project_replace 211 .ident() 212 .cloned() 213 .unwrap_or_else(|| format_ident!("__{}ProjectionOwned", ident)); 214 215 Ok(Self { 216 kind, 217 pinned_drop, 218 unpin_impl, 219 project: project.is_some(), 220 project_ref: project_ref.is_some(), 221 project_replace, 222 proj: ProjectedType { 223 vis: determine_visibility(vis), 224 mut_ident: project.unwrap_or_else(|| format_ident!("__{}Projection", ident)), 225 ref_ident: project_ref.unwrap_or_else(|| format_ident!("__{}ProjectionRef", ident)), 226 own_ident, 227 lifetime, 228 generics: proj_generics, 229 where_clause, 230 }, 231 orig: OriginalType { attrs, vis, ident, generics }, 232 pinned_fields: Vec::new(), 233 }) 234 } 235 } 236 237 #[derive(Copy, Clone, Eq, PartialEq)] 238 enum TypeKind { 239 Enum, 240 Struct, 241 } 242 243 use TypeKind::{Enum, Struct}; 244 245 struct OriginalType<'a> { 246 /// Attributes of the original type. 247 attrs: &'a [Attribute], 248 /// Visibility of the original type. 249 vis: &'a Visibility, 250 /// Name of the original type. 251 ident: &'a Ident, 252 /// Generics of the original type. 253 generics: &'a Generics, 254 } 255 256 struct ProjectedType { 257 /// Visibility of the projected types. 258 vis: Visibility, 259 /// Name of the projected type returned by `project` method. 260 mut_ident: Ident, 261 /// Name of the projected type returned by `project_ref` method. 262 ref_ident: Ident, 263 /// Name of the projected type returned by `project_replace` method. 264 own_ident: Ident, 265 /// Lifetime on the generated projected types. 266 lifetime: Lifetime, 267 /// Generics of the projected types. 268 generics: Generics, 269 /// `where` clause of the projected types. This has an additional 270 /// bound generated by `insert_lifetime_and_bound` 271 where_clause: WhereClause, 272 } 273 274 struct ProjectedVariants { 275 proj_variants: TokenStream, 276 proj_ref_variants: TokenStream, 277 proj_own_variants: TokenStream, 278 proj_arms: TokenStream, 279 proj_ref_arms: TokenStream, 280 proj_own_arms: TokenStream, 281 } 282 283 #[derive(Default)] 284 struct ProjectedFields { 285 proj_pat: TokenStream, 286 proj_body: TokenStream, 287 proj_own_body: TokenStream, 288 proj_fields: TokenStream, 289 proj_ref_fields: TokenStream, 290 proj_own_fields: TokenStream, 291 } 292 293 fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> { 294 if fields.is_empty() { 295 let msg = "#[pin_project] attribute may not be used on structs with zero fields"; 296 if let Fields::Unit = fields { Err(error!(ident, msg)) } else { Err(error!(fields, msg)) } 297 } else { 298 Ok(()) 299 } 300 } 301 302 fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> { 303 if variants.is_empty() { 304 return Err(Error::new( 305 brace_token.span, 306 "#[pin_project] attribute may not be used on enums without variants", 307 )); 308 } 309 let has_field = variants.iter().try_fold(false, |has_field, v| { 310 if let Some((_, e)) = &v.discriminant { 311 Err(error!(e, "#[pin_project] attribute may not be used on enums with discriminants")) 312 } else if let Some(attr) = v.attrs.find(PIN) { 313 Err(error!(attr, "#[pin] attribute may only be used on fields of structs or variants")) 314 } else if v.fields.is_empty() { 315 Ok(has_field) 316 } else { 317 Ok(true) 318 } 319 })?; 320 if has_field { 321 Ok(()) 322 } else { 323 Err(error!(variants, "#[pin_project] attribute may not be used on enums with zero fields")) 324 } 325 } 326 327 fn parse_struct<'a>( 328 cx: &mut Context<'a>, 329 fields: &'a Fields, 330 generate: &mut GenerateTokens, 331 ) -> Result<()> { 332 // Do this first for a better error message. 333 let packed_check = ensure_not_packed(&cx.orig, Some(fields))?; 334 335 validate_struct(cx.orig.ident, fields)?; 336 337 let ProjectedFields { 338 proj_pat, 339 proj_body, 340 proj_fields, 341 proj_ref_fields, 342 proj_own_fields, 343 proj_own_body, 344 } = match fields { 345 Fields::Named(_) => visit_fields(cx, None, fields, Delimiter::Brace)?, 346 Fields::Unnamed(_) => visit_fields(cx, None, fields, Delimiter::Parenthesis)?, 347 Fields::Unit => unreachable!(), 348 }; 349 350 let proj_ident = &cx.proj.mut_ident; 351 let proj_ref_ident = &cx.proj.ref_ident; 352 let proj_own_ident = &cx.proj.own_ident; 353 let vis = &cx.proj.vis; 354 let mut orig_generics = cx.orig.generics.clone(); 355 let orig_where_clause = orig_generics.where_clause.take(); 356 let proj_generics = &cx.proj.generics; 357 let proj_where_clause = &cx.proj.where_clause; 358 359 // For tuple structs, we need to generate `(T1, T2) where Foo: Bar` 360 // For non-tuple structs, we need to generate `where Foo: Bar { field1: T }` 361 let (where_clause_fields, where_clause_ref_fields, where_clause_own_fields) = match fields { 362 Fields::Named(_) => ( 363 quote!(#proj_where_clause #proj_fields), 364 quote!(#proj_where_clause #proj_ref_fields), 365 quote!(#orig_where_clause #proj_own_fields), 366 ), 367 Fields::Unnamed(_) => ( 368 quote!(#proj_fields #proj_where_clause;), 369 quote!(#proj_ref_fields #proj_where_clause;), 370 quote!(#proj_own_fields #orig_where_clause;), 371 ), 372 Fields::Unit => unreachable!(), 373 }; 374 375 let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx); 376 generate.extend(cx.project, quote! { 377 #proj_attrs 378 #vis struct #proj_ident #proj_generics #where_clause_fields 379 }); 380 generate.extend(cx.project_ref, quote! { 381 #proj_ref_attrs 382 #vis struct #proj_ref_ident #proj_generics #where_clause_ref_fields 383 }); 384 if cx.project_replace.span().is_some() { 385 generate.extend(cx.project_replace.ident().is_some(), quote! { 386 #proj_own_attrs 387 #vis struct #proj_own_ident #orig_generics #where_clause_own_fields 388 }); 389 } 390 391 let proj_mut_body = quote! { 392 let Self #proj_pat = self.get_unchecked_mut(); 393 #proj_ident #proj_body 394 }; 395 let proj_ref_body = quote! { 396 let Self #proj_pat = self.get_ref(); 397 #proj_ref_ident #proj_body 398 }; 399 let proj_own_body = quote! { 400 let Self #proj_pat = &mut *__self_ptr; 401 #proj_own_body 402 }; 403 generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body)); 404 405 generate.extend(false, packed_check); 406 Ok(()) 407 } 408 409 fn parse_enum<'a>( 410 cx: &mut Context<'a>, 411 DataEnum { brace_token, variants, .. }: &'a DataEnum, 412 generate: &mut GenerateTokens, 413 ) -> Result<()> { 414 if let ProjReplace::Unnamed { span } = &cx.project_replace { 415 return Err(Error::new( 416 *span, 417 "`project_replace` argument requires a value when used on enums", 418 )); 419 } 420 421 // #[repr(packed)] cannot be apply on enums and will be rejected by rustc. 422 // However, we should not rely on the behavior of rustc that rejects this. 423 // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001 424 // 425 // Do this first for a better error message. 426 ensure_not_packed(&cx.orig, None)?; 427 428 validate_enum(*brace_token, variants)?; 429 430 let ProjectedVariants { 431 proj_variants, 432 proj_ref_variants, 433 proj_own_variants, 434 proj_arms, 435 proj_ref_arms, 436 proj_own_arms, 437 } = visit_variants(cx, variants)?; 438 439 let proj_ident = &cx.proj.mut_ident; 440 let proj_ref_ident = &cx.proj.ref_ident; 441 let proj_own_ident = &cx.proj.own_ident; 442 let vis = &cx.proj.vis; 443 let mut orig_generics = cx.orig.generics.clone(); 444 let orig_where_clause = orig_generics.where_clause.take(); 445 let proj_generics = &cx.proj.generics; 446 let proj_where_clause = &cx.proj.where_clause; 447 448 let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx); 449 if cx.project { 450 generate.extend(true, quote! { 451 #proj_attrs 452 #vis enum #proj_ident #proj_generics #proj_where_clause { 453 #proj_variants 454 } 455 }); 456 } 457 if cx.project_ref { 458 generate.extend(true, quote! { 459 #proj_ref_attrs 460 #vis enum #proj_ref_ident #proj_generics #proj_where_clause { 461 #proj_ref_variants 462 } 463 }); 464 } 465 if cx.project_replace.ident().is_some() { 466 generate.extend(true, quote! { 467 #proj_own_attrs 468 #vis enum #proj_own_ident #orig_generics #orig_where_clause { 469 #proj_own_variants 470 } 471 }); 472 } 473 474 let proj_mut_body = quote! { 475 match self.get_unchecked_mut() { 476 #proj_arms 477 } 478 }; 479 let proj_ref_body = quote! { 480 match self.get_ref() { 481 #proj_ref_arms 482 } 483 }; 484 let proj_own_body = quote! { 485 match &mut *__self_ptr { 486 #proj_own_arms 487 } 488 }; 489 generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body)); 490 491 Ok(()) 492 } 493 494 fn visit_variants<'a>(cx: &mut Context<'a>, variants: &'a Variants) -> Result<ProjectedVariants> { 495 let mut proj_variants = TokenStream::new(); 496 let mut proj_ref_variants = TokenStream::new(); 497 let mut proj_own_variants = TokenStream::new(); 498 let mut proj_arms = TokenStream::new(); 499 let mut proj_ref_arms = TokenStream::new(); 500 let mut proj_own_arms = TokenStream::new(); 501 502 for Variant { ident, fields, .. } in variants { 503 let ProjectedFields { 504 proj_pat, 505 proj_body, 506 proj_fields, 507 proj_ref_fields, 508 proj_own_fields, 509 proj_own_body, 510 } = match fields { 511 Fields::Named(_) => visit_fields(cx, Some(ident), fields, Delimiter::Brace)?, 512 Fields::Unnamed(_) => visit_fields(cx, Some(ident), fields, Delimiter::Parenthesis)?, 513 Fields::Unit => ProjectedFields { 514 proj_own_body: proj_own_body(cx, Some(ident), None, &[]), 515 ..ProjectedFields::default() 516 }, 517 }; 518 519 let proj_ident = &cx.proj.mut_ident; 520 let proj_ref_ident = &cx.proj.ref_ident; 521 proj_variants.extend(quote! { 522 #ident #proj_fields, 523 }); 524 proj_ref_variants.extend(quote! { 525 #ident #proj_ref_fields, 526 }); 527 proj_own_variants.extend(quote! { 528 #ident #proj_own_fields, 529 }); 530 proj_arms.extend(quote! { 531 Self::#ident #proj_pat => #proj_ident::#ident #proj_body, 532 }); 533 proj_ref_arms.extend(quote! { 534 Self::#ident #proj_pat => #proj_ref_ident::#ident #proj_body, 535 }); 536 proj_own_arms.extend(quote! { 537 Self::#ident #proj_pat => { #proj_own_body } 538 }); 539 } 540 541 Ok(ProjectedVariants { 542 proj_variants, 543 proj_ref_variants, 544 proj_own_variants, 545 proj_arms, 546 proj_ref_arms, 547 proj_own_arms, 548 }) 549 } 550 551 fn visit_fields<'a>( 552 cx: &mut Context<'a>, 553 variant_ident: Option<&Ident>, 554 fields: &'a Fields, 555 delim: Delimiter, 556 ) -> Result<ProjectedFields> { 557 fn surround(delim: Delimiter, tokens: TokenStream) -> TokenStream { 558 Group::new(delim, tokens).into_token_stream() 559 } 560 561 let mut proj_pat = TokenStream::new(); 562 let mut proj_body = TokenStream::new(); 563 let mut proj_fields = TokenStream::new(); 564 let mut proj_ref_fields = TokenStream::new(); 565 let mut proj_own_fields = TokenStream::new(); 566 let mut proj_move = TokenStream::new(); 567 let mut pinned_bindings = Vec::with_capacity(fields.len()); 568 569 for (i, Field { attrs, vis, ident, colon_token, ty }) in fields.iter().enumerate() { 570 let binding = ident.clone().unwrap_or_else(|| format_ident!("_{}", i)); 571 proj_pat.extend(quote!(#binding,)); 572 let lifetime = &cx.proj.lifetime; 573 if attrs.position_exact(PIN)?.is_some() { 574 proj_fields.extend(quote! { 575 #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime mut (#ty)>, 576 }); 577 proj_ref_fields.extend(quote! { 578 #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime (#ty)>, 579 }); 580 proj_own_fields.extend(quote! { 581 #vis #ident #colon_token ::pin_project::__private::PhantomData<#ty>, 582 }); 583 proj_body.extend(quote! { 584 #ident #colon_token ::pin_project::__private::Pin::new_unchecked(#binding), 585 }); 586 proj_move.extend(quote! { 587 #ident #colon_token ::pin_project::__private::PhantomData, 588 }); 589 590 cx.pinned_fields.push(ty); 591 pinned_bindings.push(binding); 592 } else { 593 proj_fields.extend(quote! { 594 #vis #ident #colon_token &#lifetime mut (#ty), 595 }); 596 proj_ref_fields.extend(quote! { 597 #vis #ident #colon_token &#lifetime (#ty), 598 }); 599 proj_own_fields.extend(quote! { 600 #vis #ident #colon_token #ty, 601 }); 602 proj_body.extend(quote! { 603 #binding, 604 }); 605 proj_move.extend(quote! { 606 #ident #colon_token ::pin_project::__private::ptr::read(#binding), 607 }); 608 } 609 } 610 611 let proj_pat = surround(delim, proj_pat); 612 let proj_body = surround(delim, proj_body); 613 let proj_fields = surround(delim, proj_fields); 614 let proj_ref_fields = surround(delim, proj_ref_fields); 615 let proj_own_fields = surround(delim, proj_own_fields); 616 617 let proj_move = Group::new(delim, proj_move); 618 let proj_own_body = proj_own_body(cx, variant_ident, Some(&proj_move), &pinned_bindings); 619 620 Ok(ProjectedFields { 621 proj_pat, 622 proj_body, 623 proj_own_body, 624 proj_fields, 625 proj_ref_fields, 626 proj_own_fields, 627 }) 628 } 629 630 /// Generates the processing that `project_replace` does for the struct or each variant. 631 /// 632 /// Note: `pinned_fields` must be in declaration order. 633 fn proj_own_body( 634 cx: &Context<'_>, 635 variant_ident: Option<&Ident>, 636 proj_move: Option<&Group>, 637 pinned_fields: &[Ident], 638 ) -> TokenStream { 639 let ident = &cx.proj.own_ident; 640 let proj_own = match variant_ident { 641 Some(variant_ident) => quote!(#ident::#variant_ident), 642 None => quote!(#ident), 643 }; 644 645 // The fields of the struct and the active enum variant are dropped 646 // in declaration order. 647 // Refs: https://doc.rust-lang.org/reference/destructors.html 648 let pinned_fields = pinned_fields.iter().rev(); 649 650 quote! { 651 // First, extract all the unpinned fields. 652 let __result = #proj_own #proj_move; 653 654 // Now create guards to drop all the pinned fields. 655 // 656 // Due to a compiler bug (https://github.com/rust-lang/rust/issues/47949) 657 // this must be in its own scope, or else `__result` will not be dropped 658 // if any of the destructors panic. 659 { 660 #( 661 let __guard = ::pin_project::__private::UnsafeDropInPlaceGuard(#pinned_fields); 662 )* 663 } 664 665 // Finally, return the result. 666 __result 667 } 668 } 669 670 /// Creates `Unpin` implementation for the original type. 671 /// 672 /// The kind of `Unpin` impl generated depends on `unpin_impl` field: 673 /// * `UnpinImpl::Unsafe` - Implements `Unpin` via `UnsafeUnpin` impl. 674 /// * `UnpinImpl::Negative` - Generates `Unpin` impl with bounds that will never be true. 675 /// * `UnpinImpl::Default` - Generates `Unpin` impl that requires `Unpin` for all pinned fields. 676 fn make_unpin_impl(cx: &Context<'_>) -> TokenStream { 677 match cx.unpin_impl { 678 UnpinImpl::Unsafe(span) => { 679 let mut proj_generics = cx.proj.generics.clone(); 680 let orig_ident = cx.orig.ident; 681 let lifetime = &cx.proj.lifetime; 682 683 // Make the error message highlight `UnsafeUnpin` argument. 684 proj_generics.make_where_clause().predicates.push(parse_quote_spanned! { span => 685 ::pin_project::__private::Wrapper<#lifetime, Self>: ::pin_project::UnsafeUnpin 686 }); 687 688 let (impl_generics, _, where_clause) = proj_generics.split_for_impl(); 689 let ty_generics = cx.orig.generics.split_for_impl().1; 690 691 quote_spanned! { span => 692 impl #impl_generics ::pin_project::__private::Unpin for #orig_ident #ty_generics 693 #where_clause 694 { 695 } 696 } 697 } 698 UnpinImpl::Negative(span) => { 699 let mut proj_generics = cx.proj.generics.clone(); 700 let orig_ident = cx.orig.ident; 701 let lifetime = &cx.proj.lifetime; 702 703 proj_generics.make_where_clause().predicates.push(parse_quote! { 704 ::pin_project::__private::Wrapper< 705 #lifetime, ::pin_project::__private::PhantomPinned 706 >: ::pin_project::__private::Unpin 707 }); 708 709 let (proj_impl_generics, _, proj_where_clause) = proj_generics.split_for_impl(); 710 let ty_generics = cx.orig.generics.split_for_impl().1; 711 712 // For interoperability with `forbid(unsafe_code)`, `unsafe` token should be 713 // call-site span. 714 let unsafety = <Token![unsafe]>::default(); 715 quote_spanned! { span => 716 impl #proj_impl_generics ::pin_project::__private::Unpin 717 for #orig_ident #ty_generics 718 #proj_where_clause 719 { 720 } 721 722 // Generate a dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it. 723 // 724 // To ensure that users don't accidentally write a non-functional `UnsafeUnpin` 725 // impls, we emit one ourselves. If the user ends up writing an `UnsafeUnpin` 726 // impl, they'll get a "conflicting implementations of trait" error when 727 // coherence checks are run. 728 #[doc(hidden)] 729 #unsafety impl #proj_impl_generics ::pin_project::UnsafeUnpin 730 for #orig_ident #ty_generics 731 #proj_where_clause 732 { 733 } 734 } 735 } 736 UnpinImpl::Default => { 737 let mut full_where_clause = cx.orig.generics.where_clause.clone().unwrap(); 738 739 // Generate a field in our new struct for every 740 // pinned field in the original type. 741 let fields = cx.pinned_fields.iter().enumerate().map(|(i, ty)| { 742 let field_ident = format_ident!("__field{}", i); 743 quote!(#field_ident: #ty) 744 }); 745 746 // We could try to determine the subset of type parameters 747 // and lifetimes that are actually used by the pinned fields 748 // (as opposed to those only used by unpinned fields). 749 // However, this would be tricky and error-prone, since 750 // it's possible for users to create types that would alias 751 // with generic parameters (e.g. 'struct T'). 752 // 753 // Instead, we generate a use of every single type parameter 754 // and lifetime used in the original struct. For type parameters, 755 // we generate code like this: 756 // 757 // ```rust 758 // struct AlwaysUnpin<T: ?Sized>(PhantomData<T>) {} 759 // impl<T: ?Sized> Unpin for AlwaysUnpin<T> {} 760 // 761 // ... 762 // _field: AlwaysUnpin<(A, B, C)> 763 // ``` 764 // 765 // This ensures that any unused type parameters 766 // don't end up with `Unpin` bounds. 767 let lifetime_fields = cx.orig.generics.lifetimes().enumerate().map( 768 |(i, LifetimeDef { lifetime, .. })| { 769 let field_ident = format_ident!("__lifetime{}", i); 770 quote!(#field_ident: &#lifetime ()) 771 }, 772 ); 773 774 let orig_ident = cx.orig.ident; 775 let struct_ident = format_ident!("__{}", orig_ident); 776 let vis = cx.orig.vis; 777 let lifetime = &cx.proj.lifetime; 778 let type_params = cx.orig.generics.type_params().map(|t| &t.ident); 779 let proj_generics = &cx.proj.generics; 780 let (proj_impl_generics, proj_ty_generics, _) = proj_generics.split_for_impl(); 781 let (_, ty_generics, where_clause) = cx.orig.generics.split_for_impl(); 782 783 full_where_clause.predicates.push(parse_quote! { 784 #struct_ident #proj_ty_generics: ::pin_project::__private::Unpin 785 }); 786 787 quote! { 788 // This needs to have the same visibility as the original type, 789 // due to the limitations of the 'public in private' error. 790 // 791 // Our goal is to implement the public trait `Unpin` for 792 // a potentially public user type. Because of this, rust 793 // requires that any types mentioned in the where clause of 794 // our `Unpin` impl also be public. This means that our generated 795 // `__UnpinStruct` type must also be public. 796 // However, we ensure that the user can never actually reference 797 // this 'public' type by creating this type in the inside of `const`. 798 #[allow(missing_debug_implementations)] 799 #vis struct #struct_ident #proj_generics #where_clause { 800 __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin< 801 #lifetime, (#(::pin_project::__private::PhantomData<#type_params>),*) 802 >, 803 804 #(#fields,)* 805 #(#lifetime_fields,)* 806 } 807 808 impl #proj_impl_generics ::pin_project::__private::Unpin 809 for #orig_ident #ty_generics 810 #full_where_clause 811 { 812 } 813 814 // Generate a dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it. 815 // 816 // To ensure that users don't accidentally write a non-functional `UnsafeUnpin` 817 // impls, we emit one ourselves. If the user ends up writing an `UnsafeUnpin` 818 // impl, they'll get a "conflicting implementations of trait" error when 819 // coherence checks are run. 820 #[doc(hidden)] 821 unsafe impl #proj_impl_generics ::pin_project::UnsafeUnpin 822 for #orig_ident #ty_generics 823 #full_where_clause 824 { 825 } 826 } 827 } 828 } 829 } 830 831 /// Creates `Drop` implementation for the original type. 832 /// 833 /// The kind of `Drop` impl generated depends on `pinned_drop` field: 834 /// * `Some` - implements `Drop` via `PinnedDrop` impl. 835 /// * `None` - generates code that ensures that `Drop` trait is not implemented, 836 /// instead of generating `Drop` impl. 837 fn make_drop_impl(cx: &Context<'_>) -> TokenStream { 838 let ident = cx.orig.ident; 839 let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl(); 840 841 if let Some(span) = cx.pinned_drop { 842 // For interoperability with `forbid(unsafe_code)`, `unsafe` token should be 843 // call-site span. 844 let unsafety = <Token![unsafe]>::default(); 845 quote_spanned! { span => 846 impl #impl_generics ::pin_project::__private::Drop for #ident #ty_generics 847 #where_clause 848 { 849 fn drop(&mut self) { 850 #unsafety { 851 // Safety - we're in 'drop', so we know that 'self' will 852 // never move again. 853 let __pinned_self = ::pin_project::__private::Pin::new_unchecked(self); 854 // We call `pinned_drop` only once. Since `PinnedDrop::drop` 855 // is an unsafe method and a private API, it is never called again in safe 856 // code *unless the user uses a maliciously crafted macro*. 857 ::pin_project::__private::PinnedDrop::drop(__pinned_self); 858 } 859 } 860 } 861 } 862 } else { 863 // If the user does not provide a `PinnedDrop` impl, 864 // we need to ensure that they don't provide a `Drop` impl of their 865 // own. 866 // Based on https://github.com/upsuper/assert-impl/blob/f503255b292ab0ba8d085b657f4065403cfa46eb/src/lib.rs#L80-L87 867 // 868 // We create a new identifier for each struct, so that the traits 869 // for different types do not conflict with each other. 870 // 871 // Another approach would be to provide an empty Drop impl, 872 // which would conflict with a user-provided Drop impl. 873 // However, this would trigger the compiler's special handling 874 // of Drop types (e.g. fields cannot be moved out of a Drop type). 875 // This approach prevents the creation of needless Drop impls, 876 // giving users more flexibility. 877 let trait_ident = format_ident!("{}MustNotImplDrop", ident); 878 879 quote! { 880 // There are two possible cases: 881 // 1. The user type does not implement Drop. In this case, 882 // the first blanked impl will not apply to it. This code 883 // will compile, as there is only one impl of MustNotImplDrop for the user type 884 // 2. The user type does impl Drop. This will make the blanket impl applicable, 885 // which will then conflict with the explicit MustNotImplDrop impl below. 886 // This will result in a compilation error, which is exactly what we want. 887 trait #trait_ident {} 888 #[allow(clippy::drop_bounds, drop_bounds)] 889 impl<T: ::pin_project::__private::Drop> #trait_ident for T {} 890 impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {} 891 892 // Generate a dummy impl of `PinnedDrop`, to ensure that the user cannot implement it. 893 // Since the user did not pass `PinnedDrop` to `#[pin_project]`, any `PinnedDrop` 894 // impl will not actually be called. Unfortunately, we can't detect this situation 895 // directly from either the `#[pin_project]` or `#[pinned_drop]` attributes, since 896 // we don't know what other attributes/impl may exist. 897 // 898 // To ensure that users don't accidentally write a non-functional `PinnedDrop` 899 // impls, we emit one ourselves. If the user ends up writing a `PinnedDrop` impl, 900 // they'll get a "conflicting implementations of trait" error when coherence 901 // checks are run. 902 #[doc(hidden)] 903 impl #impl_generics ::pin_project::__private::PinnedDrop for #ident #ty_generics 904 #where_clause 905 { 906 unsafe fn drop(self: ::pin_project::__private::Pin<&mut Self>) {} 907 } 908 } 909 } 910 } 911 912 /// Creates an implementation of the projection methods. 913 /// 914 /// On structs, both the `project` and `project_ref` methods are always generated, 915 /// and the `project_replace` method is only generated if `ProjReplace::span` is `Some`. 916 /// 917 /// On enums, only methods that the returned projected type is named will be generated. 918 fn make_proj_impl( 919 cx: &Context<'_>, 920 proj_body: &TokenStream, 921 proj_ref_body: &TokenStream, 922 proj_own_body: &TokenStream, 923 ) -> TokenStream { 924 let vis = &cx.proj.vis; 925 let lifetime = &cx.proj.lifetime; 926 let orig_ident = cx.orig.ident; 927 let proj_ident = &cx.proj.mut_ident; 928 let proj_ref_ident = &cx.proj.ref_ident; 929 let proj_own_ident = &cx.proj.own_ident; 930 931 let orig_ty_generics = cx.orig.generics.split_for_impl().1; 932 let proj_ty_generics = cx.proj.generics.split_for_impl().1; 933 let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl(); 934 935 let mut project = Some(quote! { 936 #vis fn project<#lifetime>( 937 self: ::pin_project::__private::Pin<&#lifetime mut Self>, 938 ) -> #proj_ident #proj_ty_generics { 939 unsafe { 940 #proj_body 941 } 942 } 943 }); 944 let mut project_ref = Some(quote! { 945 #[allow(clippy::missing_const_for_fn)] 946 #vis fn project_ref<#lifetime>( 947 self: ::pin_project::__private::Pin<&#lifetime Self>, 948 ) -> #proj_ref_ident #proj_ty_generics { 949 unsafe { 950 #proj_ref_body 951 } 952 } 953 }); 954 let mut project_replace = cx.project_replace.span().map(|span| { 955 // It is enough to only set the span of the signature. 956 let sig = quote_spanned! { span => 957 #vis fn project_replace( 958 self: ::pin_project::__private::Pin<&mut Self>, 959 __replacement: Self, 960 ) -> #proj_own_ident #orig_ty_generics 961 }; 962 quote! { 963 #sig { 964 unsafe { 965 let __self_ptr: *mut Self = self.get_unchecked_mut(); 966 967 // Destructors will run in reverse order, so next create a guard to overwrite 968 // `self` with the replacement value without calling destructors. 969 let __guard = ::pin_project::__private::UnsafeOverwriteGuard { 970 target: __self_ptr, 971 value: ::pin_project::__private::ManuallyDrop::new(__replacement), 972 }; 973 974 #proj_own_body 975 } 976 } 977 } 978 }); 979 980 if cx.kind == Enum { 981 if !cx.project { 982 project = None; 983 } 984 if !cx.project_ref { 985 project_ref = None; 986 } 987 if cx.project_replace.ident().is_none() { 988 project_replace = None; 989 } 990 } 991 992 quote! { 993 impl #impl_generics #orig_ident #ty_generics #where_clause { 994 #project 995 #project_ref 996 #project_replace 997 } 998 } 999 } 1000 1001 /// Checks that the `[repr(packed)]` attribute is not included. 1002 /// 1003 /// This currently does two checks: 1004 /// * Checks the attributes of structs to ensure there is no `[repr(packed)]`. 1005 /// * Generates a function that borrows fields without an unsafe block and 1006 /// forbidding `unaligned_references` lint. 1007 fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result<TokenStream> { 1008 for meta in orig.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) { 1009 if let Meta::List(list) = meta { 1010 if list.path.is_ident("repr") { 1011 for repr in list.nested.iter() { 1012 match repr { 1013 NestedMeta::Meta(Meta::Path(path)) 1014 | NestedMeta::Meta(Meta::List(MetaList { path, .. })) 1015 | NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, .. })) => { 1016 if path.is_ident("packed") { 1017 let msg = if fields.is_none() { 1018 // #[repr(packed)] cannot be apply on enums and will be rejected by rustc. 1019 // However, we should not rely on the behavior of rustc that rejects this. 1020 // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001 1021 "#[repr(packed)] attribute should be applied to a struct or union" 1022 } else if let NestedMeta::Meta(Meta::NameValue(..)) = repr { 1023 // #[repr(packed = "")] is not valid format of #[repr(packed)] and will be 1024 // rejected by rustc. 1025 // However, we should not rely on the behavior of rustc that rejects this. 1026 // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001 1027 "#[repr(packed)] attribute should not be name-value pair" 1028 } else { 1029 "#[pin_project] attribute may not be used on #[repr(packed)] types" 1030 }; 1031 return Err(error!(repr, msg)); 1032 } 1033 } 1034 NestedMeta::Lit(..) => {} 1035 } 1036 } 1037 } 1038 } 1039 } 1040 1041 let fields = match fields { 1042 Some(fields) => fields, 1043 None => return Ok(TokenStream::new()), 1044 }; 1045 1046 // Workaround for https://github.com/taiki-e/pin-project/issues/32 1047 // Through the tricky use of proc macros, it's possible to bypass 1048 // the above check for the `repr` attribute. 1049 // To ensure that it's impossible to use pin projections on a `#[repr(packed)]` 1050 // struct, we generate code like this: 1051 // 1052 // ```rust 1053 // #[forbid(unaligned_references)] 1054 // fn assert_not_repr_packed(val: &MyStruct) { 1055 // let _field1 = &val.field1; 1056 // let _field2 = &val.field2; 1057 // ... 1058 // let _fieldn = &val.fieldn; 1059 // } 1060 // ``` 1061 // 1062 // Taking a reference to a packed field is UB, and applying 1063 // `#[forbid(unaligned_references)]` makes sure that doing this is a hard error. 1064 // 1065 // If the struct ends up having `#[repr(packed)]` applied somehow, 1066 // this will generate an (unfriendly) error message. Under all reasonable 1067 // circumstances, we'll detect the `#[repr(packed)]` attribute, and generate 1068 // a much nicer error above. 1069 // 1070 // There is one exception: If the type of a struct field has an alignment of 1 1071 // (e.g. u8), it is always safe to take a reference to it, even if the struct 1072 // is `#[repr(packed)]`. If the struct is composed entirely of types of 1073 // alignment 1, our generated method will not trigger an error if the 1074 // struct is `#[repr(packed)]`. 1075 // 1076 // Fortunately, this should have no observable consequence - `#[repr(packed)]` 1077 // is essentially a no-op on such a type. Nevertheless, we include a test 1078 // to ensure that the compiler doesn't ever try to copy the fields on 1079 // such a struct when trying to drop it - which is reason we prevent 1080 // `#[repr(packed)]` in the first place. 1081 // 1082 // See also https://github.com/taiki-e/pin-project/pull/34. 1083 // 1084 // Note: 1085 // - pin-project v0.4.3 or later (#135, v0.4.0-v0.4.2 are already yanked for 1086 // another reason) is internally proc-macro-derive, so they are not 1087 // affected by the problem that the struct definition is rewritten by 1088 // another macro after the #[pin_project] is expanded. 1089 // So this is probably no longer necessary, but it keeps it for now. 1090 // 1091 // - Lint-based tricks aren't perfect, but they're much better than nothing: 1092 // https://github.com/taiki-e/pin-project-lite/issues/26 1093 // 1094 // - Enable both unaligned_references and safe_packed_borrows lints 1095 // because unaligned_references lint does not exist in older compilers: 1096 // https://github.com/taiki-e/pin-project-lite/pull/55 1097 // https://github.com/rust-lang/rust/pull/82525 1098 let mut field_refs = vec![]; 1099 match fields { 1100 Fields::Named(FieldsNamed { named, .. }) => { 1101 for Field { ident, .. } in named { 1102 field_refs.push(quote!(&this.#ident)); 1103 } 1104 } 1105 Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => { 1106 for (index, _) in unnamed.iter().enumerate() { 1107 let index = Index::from(index); 1108 field_refs.push(quote!(&this.#index)); 1109 } 1110 } 1111 Fields::Unit => {} 1112 } 1113 1114 let (impl_generics, ty_generics, where_clause) = orig.generics.split_for_impl(); 1115 let ident = orig.ident; 1116 Ok(quote! { 1117 #[forbid(unaligned_references, safe_packed_borrows)] 1118 fn __assert_not_repr_packed #impl_generics (this: &#ident #ty_generics) #where_clause { 1119 #(let _ = #field_refs;)* 1120 } 1121 }) 1122 } 1123