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