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