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