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