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