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