pin_project_internal/pin_project/
derive.rs

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