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