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