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