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