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: &str = "#[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 span:brace_token.span.join(),
314 message:"#[pin_project] attribute may not be used on enums without variants",
315 ));
316 }
317 let has_field: bool = variants.iter().try_fold(init:false, |has_field: bool, v: &Variant| {
318 if let Some((_, e: &Expr)) = &v.discriminant {
319 bail!(e, "#[pin_project] attribute may not be used on enums with discriminants");
320 } else if let Some(attr: &Attribute) = 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: &Brace, variants: &Punctuated, .. }: &'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}
1131