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