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