1 use proc_macro2::{Span, TokenStream};
2 use quote::{format_ident, quote, quote_spanned};
3 use syn::{
4 parse::{Parse, ParseBuffer, ParseStream},
5 visit_mut::VisitMut,
6 *,
7 };
8
9 use crate::utils::*;
10
11 use super::PIN;
12
parse_derive(input: TokenStream) -> Result<TokenStream>13 pub(super) fn parse_derive(input: TokenStream) -> Result<TokenStream> {
14 match syn::parse2(input)? {
15 Item::Struct(ItemStruct { attrs, vis, ident, generics, fields, .. }) => {
16 validate_struct(&ident, &fields)?;
17 let mut cx = Context::new(attrs, vis, ident, generics)?;
18
19 let packed_check = cx.ensure_not_packed(&fields)?;
20 let mut proj_items = cx.parse_struct(&fields)?;
21 proj_items.extend(packed_check);
22 proj_items.extend(cx.make_unpin_impl());
23 proj_items.extend(cx.make_drop_impl());
24 Ok(proj_items)
25 }
26 Item::Enum(ItemEnum { attrs, vis, ident, generics, brace_token, variants, .. }) => {
27 validate_enum(brace_token, &variants)?;
28 let mut cx = Context::new(attrs, vis, ident, generics)?;
29
30 // We don't need to check for '#[repr(packed)]',
31 // since it does not apply to enums.
32 let mut proj_items = cx.parse_enum(&variants)?;
33 proj_items.extend(cx.make_unpin_impl());
34 proj_items.extend(cx.make_drop_impl());
35 Ok(proj_items)
36 }
37 item => Err(error!(item, "#[pin_project] attribute may only be used on structs or enums")),
38 }
39 }
40
validate_struct(ident: &Ident, fields: &Fields) -> Result<()>41 fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> {
42 match fields {
43 Fields::Named(FieldsNamed { named: f, .. })
44 | Fields::Unnamed(FieldsUnnamed { unnamed: f, .. })
45 if f.is_empty() =>
46 {
47 Err(error!(
48 fields,
49 "#[pin_project] attribute may not be used on structs with zero fields"
50 ))
51 }
52 Fields::Unit => {
53 Err(error!(ident, "#[pin_project] attribute may not be used on structs with units"))
54 }
55 _ => Ok(()),
56 }
57 }
58
validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()>59 fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> {
60 if variants.is_empty() {
61 return Err(syn::Error::new(
62 brace_token.span,
63 "#[pin_project] attribute may not be used on enums without variants",
64 ));
65 }
66 let has_field = variants.iter().try_fold(false, |has_field, v| {
67 if let Some((_, e)) = &v.discriminant {
68 Err(error!(e, "#[pin_project] attribute may not be used on enums with discriminants"))
69 } else if let Some(attr) = v.attrs.find(PIN) {
70 Err(error!(attr, "#[pin] attribute may only be used on fields of structs or variants"))
71 } else if let Fields::Unit = v.fields {
72 Ok(has_field)
73 } else {
74 Ok(true)
75 }
76 })?;
77 if has_field {
78 Ok(())
79 } else {
80 Err(error!(
81 variants,
82 "#[pin_project] attribute may not be used on enums that have no field"
83 ))
84 }
85 }
86
87 #[derive(Default)]
88 struct Args {
89 pinned_drop: Option<Span>,
90 unsafe_unpin: Option<Span>,
91 }
92
93 const DUPLICATE_PIN: &str = "duplicate #[pin] attribute";
94
95 impl Args {
get(attrs: &[Attribute]) -> Result<Self>96 fn get(attrs: &[Attribute]) -> Result<Self> {
97 let mut prev: Option<(&Attribute, Result<Args>)> = None;
98
99 for attr in attrs {
100 if attr.path.is_ident(PIN) {
101 if let Some((prev_attr, prev_res)) = &prev {
102 // As the `#[pin]` attribute generated by `#[pin_project]`
103 // has the same span as `#[pin_project]`, it is possible
104 // that a useless error message will be generated.
105 let res = syn::parse2::<Self>(attr.tokens.clone());
106 let span = match (&prev_res, res) {
107 (Ok(_), Ok(_)) => unreachable!(),
108 (_, Ok(_)) => prev_attr,
109 (Ok(_), _) => attr,
110 (Err(prev_err), Err(_)) => {
111 if prev_err.to_string() == DUPLICATE_PIN {
112 attr
113 } else {
114 prev_attr
115 }
116 }
117 };
118 return Err(error!(span, DUPLICATE_PIN));
119 }
120 prev = Some((attr, syn::parse2::<Self>(attr.tokens.clone())));
121 }
122 }
123
124 // This `unwrap` only fails if another macro removes `#[pin]`.
125 prev.unwrap().1
126 }
127 }
128
129 impl Parse for Args {
parse(input: ParseStream<'_>) -> Result<Self>130 fn parse(input: ParseStream<'_>) -> Result<Self> {
131 fn parse_input(input: ParseStream<'_>) -> Result<ParseBuffer<'_>> {
132 // Extracts `#args` from `(#private(#args))`.
133 if let Ok(content) = input.parenthesized() {
134 if let Ok(private) = content.parse::<Ident>() {
135 if private == CURRENT_PRIVATE_MODULE {
136 if let Ok(args) = content.parenthesized() {
137 return Ok(args);
138 }
139 }
140 }
141 }
142
143 // If this fails, it means that there is a `#[pin]` attribute
144 // inserted by something other than #[pin_project] attribute.
145 Err(error!(TokenStream::new(), DUPLICATE_PIN))
146 }
147
148 let input = parse_input(input)?;
149 let mut args = Self::default();
150 while !input.is_empty() {
151 let ident = input.parse::<Ident>()?;
152 match &*ident.to_string() {
153 "PinnedDrop" => {
154 if args.pinned_drop.is_some() {
155 return Err(error!(ident, "duplicate `PinnedDrop` argument"));
156 }
157 args.pinned_drop = Some(ident.span());
158 }
159 "UnsafeUnpin" => {
160 if args.unsafe_unpin.is_some() {
161 return Err(error!(ident, "duplicate `UnsafeUnpin` argument"));
162 }
163 args.unsafe_unpin = Some(ident.span());
164 }
165 _ => return Err(error!(ident, "unexpected argument: {}", ident)),
166 }
167
168 if !input.is_empty() {
169 let _: token::Comma = input.parse()?;
170 }
171 }
172
173 Ok(args)
174 }
175 }
176
177 struct OriginalType {
178 /// Attributes of the original type.
179 attrs: Vec<Attribute>,
180 /// Visibility of the original type.
181 vis: Visibility,
182 /// Name of the original type.
183 ident: Ident,
184 /// Generics of the original type.
185 generics: Generics,
186 }
187
188 struct ProjectedType {
189 /// Visibility of the projected type.
190 vis: Visibility,
191 /// Name of the projected type returned by `project` method.
192 mut_ident: Ident,
193 /// Name of the projected type returned by `project_ref` method.
194 ref_ident: Ident,
195 /// Lifetime on the generated projected type.
196 lifetime: Lifetime,
197 /// Generics of the projected type.
198 generics: Generics,
199 }
200
201 struct Context {
202 orig: OriginalType,
203 proj: ProjectedType,
204 /// Types of the pinned fields.
205 pinned_fields: Vec<Type>,
206 /// `PinnedDrop` attribute.
207 pinned_drop: Option<Span>,
208 /// `UnsafeUnpin` attribute.
209 unsafe_unpin: Option<Span>,
210 }
211
212 impl Context {
new( attrs: Vec<Attribute>, vis: Visibility, ident: Ident, mut generics: Generics, ) -> Result<Self>213 fn new(
214 attrs: Vec<Attribute>,
215 vis: Visibility,
216 ident: Ident,
217 mut generics: Generics,
218 ) -> Result<Self> {
219 let Args { pinned_drop, unsafe_unpin } = Args::get(&attrs)?;
220
221 {
222 let ty_generics = generics.split_for_impl().1;
223 let self_ty = syn::parse_quote!(#ident #ty_generics);
224 let mut visitor = ReplaceReceiver::new(&self_ty);
225 visitor.visit_where_clause_mut(generics.make_where_clause());
226 }
227
228 let mut lifetime_name = String::from(DEFAULT_LIFETIME_NAME);
229 determine_lifetime_name(&mut lifetime_name, &generics.params);
230 let lifetime = Lifetime::new(&lifetime_name, Span::call_site());
231
232 let mut proj_generics = generics.clone();
233 insert_lifetime(&mut proj_generics, lifetime.clone());
234
235 Ok(Self {
236 proj: ProjectedType {
237 vis: determine_visibility(&vis),
238 mut_ident: proj_ident(&ident, Mutable),
239 ref_ident: proj_ident(&ident, Immutable),
240 lifetime,
241 generics: proj_generics,
242 },
243 orig: OriginalType { attrs, vis, ident, generics },
244 pinned_drop,
245 unsafe_unpin,
246 pinned_fields: Vec::new(),
247 })
248 }
249
parse_struct(&mut self, fields: &Fields) -> Result<TokenStream>250 fn parse_struct(&mut self, fields: &Fields) -> Result<TokenStream> {
251 let (proj_pat, proj_init, proj_fields, proj_ref_fields) = match fields {
252 Fields::Named(fields) => self.visit_named(fields)?,
253 Fields::Unnamed(fields) => self.visit_unnamed(fields, true)?,
254 Fields::Unit => unreachable!(),
255 };
256
257 let orig_ident = &self.orig.ident;
258 let proj_ident = &self.proj.mut_ident;
259 let proj_ref_ident = &self.proj.ref_ident;
260 let vis = &self.proj.vis;
261 let proj_generics = &self.proj.generics;
262 let where_clause = self.orig.generics.split_for_impl().2;
263
264 let mut proj_items = quote! {
265 #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
266 #[allow(dead_code)] // This lint warns unused fields/variants.
267 #vis struct #proj_ident #proj_generics #where_clause #proj_fields
268 #[allow(dead_code)] // This lint warns unused fields/variants.
269 #vis struct #proj_ref_ident #proj_generics #where_clause #proj_ref_fields
270 };
271
272 let proj_body = quote! {
273 let #orig_ident #proj_pat = self.get_unchecked_mut();
274 #proj_ident #proj_init
275 };
276 let proj_ref_body = quote! {
277 let #orig_ident #proj_pat = self.get_ref();
278 #proj_ref_ident #proj_init
279 };
280
281 proj_items.extend(self.make_proj_impl(&proj_body, &proj_ref_body));
282
283 Ok(proj_items)
284 }
285
parse_enum(&mut self, variants: &Variants) -> Result<TokenStream>286 fn parse_enum(&mut self, variants: &Variants) -> Result<TokenStream> {
287 let (proj_variants, proj_ref_variants, proj_arms, proj_ref_arms) =
288 self.visit_variants(variants)?;
289
290 let proj_ident = &self.proj.mut_ident;
291 let proj_ref_ident = &self.proj.ref_ident;
292 let vis = &self.proj.vis;
293 let proj_generics = &self.proj.generics;
294 let where_clause = self.orig.generics.split_for_impl().2;
295
296 let mut proj_items = quote! {
297 #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
298 #[allow(dead_code)] // This lint warns unused fields/variants.
299 #vis enum #proj_ident #proj_generics #where_clause {
300 #proj_variants
301 }
302 #[allow(dead_code)] // This lint warns unused fields/variants.
303 #vis enum #proj_ref_ident #proj_generics #where_clause {
304 #proj_ref_variants
305 }
306 };
307
308 let proj_body = quote! {
309 match self.get_unchecked_mut() {
310 #proj_arms
311 }
312 };
313 let proj_ref_body = quote! {
314 match self.get_ref() {
315 #proj_ref_arms
316 }
317 };
318
319 proj_items.extend(self.make_proj_impl(&proj_body, &proj_ref_body));
320
321 Ok(proj_items)
322 }
323
visit_variants( &mut self, variants: &Variants, ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)>324 fn visit_variants(
325 &mut self,
326 variants: &Variants,
327 ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> {
328 let mut proj_variants = TokenStream::new();
329 let mut proj_ref_variants = TokenStream::new();
330 let mut proj_arms = TokenStream::new();
331 let mut proj_ref_arms = TokenStream::new();
332 for Variant { ident, fields, .. } in variants {
333 let (proj_pat, proj_body, proj_fields, proj_ref_fields) = match fields {
334 Fields::Named(fields) => self.visit_named(fields)?,
335 Fields::Unnamed(fields) => self.visit_unnamed(fields, false)?,
336 Fields::Unit => {
337 (TokenStream::new(), TokenStream::new(), TokenStream::new(), TokenStream::new())
338 }
339 };
340
341 let orig_ident = &self.orig.ident;
342 let proj_ident = &self.proj.mut_ident;
343 let proj_ref_ident = &self.proj.ref_ident;
344 proj_variants.extend(quote! {
345 #ident #proj_fields,
346 });
347 proj_ref_variants.extend(quote! {
348 #ident #proj_ref_fields,
349 });
350 proj_arms.extend(quote! {
351 #orig_ident::#ident #proj_pat => {
352 #proj_ident::#ident #proj_body
353 }
354 });
355 proj_ref_arms.extend(quote! {
356 #orig_ident::#ident #proj_pat => {
357 #proj_ref_ident::#ident #proj_body
358 }
359 });
360 }
361
362 Ok((proj_variants, proj_ref_variants, proj_arms, proj_ref_arms))
363 }
364
365 fn visit_named(
366 &mut self,
367 FieldsNamed { named: fields, .. }: &FieldsNamed,
368 ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> {
369 let mut proj_pat = Vec::with_capacity(fields.len());
370 let mut proj_body = Vec::with_capacity(fields.len());
371 let mut proj_fields = Vec::with_capacity(fields.len());
372 let mut proj_ref_fields = Vec::with_capacity(fields.len());
373 for Field { attrs, vis, ident, ty, .. } in fields {
374 if attrs.find_exact(PIN)?.is_some() {
375 self.pinned_fields.push(ty.clone());
376
377 let lifetime = &self.proj.lifetime;
378 proj_fields.push(quote! {
379 #vis #ident: ::core::pin::Pin<&#lifetime mut (#ty)>
380 });
381 proj_ref_fields.push(quote! {
382 #vis #ident: ::core::pin::Pin<&#lifetime (#ty)>
383 });
384 proj_body.push(quote! {
385 #ident: ::core::pin::Pin::new_unchecked(#ident)
386 });
387 } else {
388 let lifetime = &self.proj.lifetime;
389 proj_fields.push(quote! {
390 #vis #ident: &#lifetime mut (#ty)
391 });
392 proj_ref_fields.push(quote! {
393 #vis #ident: &#lifetime (#ty)
394 });
395 proj_body.push(quote! {
396 #ident
397 });
398 }
399 proj_pat.push(ident);
400 }
401
402 let proj_pat = quote!({ #(#proj_pat),* });
403 let proj_body = quote!({ #(#proj_body),* });
404 let proj_fields = quote!({ #(#proj_fields),* });
405 let proj_ref_fields = quote!({ #(#proj_ref_fields),* });
406
407 Ok((proj_pat, proj_body, proj_fields, proj_ref_fields))
408 }
409
410 fn visit_unnamed(
411 &mut self,
412 FieldsUnnamed { unnamed: fields, .. }: &FieldsUnnamed,
413 is_struct: bool,
414 ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> {
415 let mut proj_pat = Vec::with_capacity(fields.len());
416 let mut proj_body = Vec::with_capacity(fields.len());
417 let mut proj_fields = Vec::with_capacity(fields.len());
418 let mut proj_ref_fields = Vec::with_capacity(fields.len());
419 for (i, Field { attrs, vis, ty, .. }) in fields.iter().enumerate() {
420 let id = format_ident!("_{}", i);
421 if attrs.find_exact(PIN)?.is_some() {
422 self.pinned_fields.push(ty.clone());
423
424 let lifetime = &self.proj.lifetime;
425 proj_fields.push(quote! {
426 #vis ::core::pin::Pin<&#lifetime mut (#ty)>
427 });
428 proj_ref_fields.push(quote! {
429 #vis ::core::pin::Pin<&#lifetime (#ty)>
430 });
431 proj_body.push(quote! {
432 ::core::pin::Pin::new_unchecked(#id)
433 });
434 } else {
435 let lifetime = &self.proj.lifetime;
436 proj_fields.push(quote! {
437 #vis &#lifetime mut (#ty)
438 });
439 proj_ref_fields.push(quote! {
440 #vis &#lifetime (#ty)
441 });
442 proj_body.push(quote! {
443 #id
444 });
445 }
446 proj_pat.push(id);
447 }
448
449 let proj_pat = quote!((#(#proj_pat),*));
450 let proj_body = quote!((#(#proj_body),*));
451 let (proj_fields, proj_ref_fields) = if is_struct {
452 (quote!((#(#proj_fields),*);), quote!((#(#proj_ref_fields),*);))
453 } else {
454 (quote!((#(#proj_fields),*)), quote!((#(#proj_ref_fields),*)))
455 };
456
457 Ok((proj_pat, proj_body, proj_fields, proj_ref_fields))
458 }
459
460 /// Creates conditional `Unpin` implementation for original type.
make_unpin_impl(&mut self) -> TokenStream461 fn make_unpin_impl(&mut self) -> TokenStream {
462 if let Some(unsafe_unpin) = self.unsafe_unpin {
463 let mut proj_generics = self.proj.generics.clone();
464 let orig_ident = &self.orig.ident;
465 let lifetime = &self.proj.lifetime;
466
467 let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site());
468 proj_generics.make_where_clause().predicates.push(
469 // Make the error message highlight `UnsafeUnpin` argument.
470 syn::parse2(quote_spanned! { unsafe_unpin =>
471 ::pin_project::#private::Wrapper<#lifetime, Self>: ::pin_project::UnsafeUnpin
472 })
473 .unwrap(),
474 );
475
476 let (impl_generics, _, where_clause) = proj_generics.split_for_impl();
477 let ty_generics = self.orig.generics.split_for_impl().1;
478
479 quote! {
480 #[allow(single_use_lifetimes)]
481 impl #impl_generics ::core::marker::Unpin for #orig_ident #ty_generics #where_clause {}
482 }
483 } else {
484 let mut full_where_clause = self.orig.generics.where_clause.as_ref().cloned().unwrap();
485 let orig_ident = &self.orig.ident;
486
487 let make_span = || {
488 #[cfg(pin_project_show_unpin_struct)]
489 {
490 proc_macro::Span::def_site().into()
491 }
492 #[cfg(not(pin_project_show_unpin_struct))]
493 {
494 Span::call_site()
495 }
496 };
497
498 let struct_ident = format_ident!("__{}", orig_ident, span = make_span());
499
500 // Generate a field in our new struct for every
501 // pinned field in the original type.
502 let fields: Vec<_> = self
503 .pinned_fields
504 .iter()
505 .enumerate()
506 .map(|(i, ty)| {
507 let field_ident = format_ident!("__field{}", i);
508 quote! {
509 #field_ident: #ty
510 }
511 })
512 .collect();
513
514 // We could try to determine the subset of type parameters
515 // and lifetimes that are actually used by the pinned fields
516 // (as opposed to those only used by unpinned fields).
517 // However, this would be tricky and error-prone, since
518 // it's possible for users to create types that would alias
519 // with generic parameters (e.g. 'struct T').
520 //
521 // Instead, we generate a use of every single type parameter
522 // and lifetime used in the original struct. For type parameters,
523 // we generate code like this:
524 //
525 // ```rust
526 // struct AlwaysUnpin<T: ?Sized>(PhantomData<T>) {}
527 // impl<T: ?Sized> Unpin for AlwaysUnpin<T> {}
528 //
529 // ...
530 // _field: AlwaysUnpin<(A, B, C)>
531 // ```
532 //
533 // This ensures that any unused type parameters
534 // don't end up with Unpin bounds.
535 let lifetime_fields: Vec<_> = self
536 .orig
537 .generics
538 .lifetimes()
539 .enumerate()
540 .map(|(i, LifetimeDef { lifetime, .. })| {
541 let field_ident = format_ident!("__lifetime{}", i);
542 quote! {
543 #field_ident: &#lifetime ()
544 }
545 })
546 .collect();
547
548 let scope_ident = format_ident!("__unpin_scope_{}", orig_ident);
549
550 let vis = &self.orig.vis;
551 let lifetime = &self.proj.lifetime;
552 let type_params: Vec<_> = self.orig.generics.type_params().map(|t| &t.ident).collect();
553 let proj_generics = &self.proj.generics;
554 let (impl_generics, proj_ty_generics, _) = proj_generics.split_for_impl();
555 let (_, ty_generics, where_clause) = self.orig.generics.split_for_impl();
556
557 full_where_clause.predicates.push(syn::parse_quote! {
558 #struct_ident #proj_ty_generics: ::core::marker::Unpin
559 });
560
561 let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site());
562 let inner_data = quote! {
563 // This needs to have the same visibility as the original type,
564 // due to the limitations of the 'public in private' error.
565 //
566 // Out goal is to implement the public trait Unpin for
567 // a potentially public user type. Because of this, rust
568 // requires that any types mentioned in the where clause of
569 // our Unpin impl also be public. This means that our generated
570 // 'UnpinStruct' type must also be public. However, we take
571 // steps to ensure that the user can never actually reference
572 // this 'public' type. These steps are described below.
573 //
574 // See also https://github.com/taiki-e/pin-project/pull/53.
575 #vis struct #struct_ident #proj_generics #where_clause {
576 __pin_project_use_generics: ::pin_project::#private::AlwaysUnpin<#lifetime, (#(#type_params),*)>,
577
578 #(#fields,)*
579 #(#lifetime_fields,)*
580 }
581
582 impl #impl_generics ::core::marker::Unpin for #orig_ident #ty_generics #full_where_clause {}
583 };
584
585 if cfg!(pin_project_show_unpin_struct) {
586 // On nightly, we use def-site hygiene to make it impossible
587 // for user code to refer to any of the types we define.
588 // This allows us to omit wrapping the generated types
589 // in an fn() scope, allowing rustdoc to properly document
590 // them.
591 inner_data
592 } else {
593 // When we're not on nightly, we need to create an enclosing fn() scope
594 // for all of our generated items. This makes it impossible for
595 // user code to refer to any of our generated types, but has
596 // the advantage of preventing Rustdoc from displaying
597 // docs for any of our types. In particular, users cannot see
598 // the automatically generated Unpin impl for the 'UnpinStruct$Name' types.
599 quote! {
600 #[allow(non_snake_case)]
601 fn #scope_ident() {
602 #inner_data
603 }
604 }
605 }
606 }
607 }
608
609 /// Creates `Drop` implementation for original type.
make_drop_impl(&self) -> TokenStream610 fn make_drop_impl(&self) -> TokenStream {
611 let ident = &self.orig.ident;
612 let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl();
613
614 let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site());
615 if let Some(pinned_drop) = self.pinned_drop {
616 // Make the error message highlight `PinnedDrop` argument.
617 // See https://github.com/taiki-e/pin-project/issues/16#issuecomment-513586812
618 // for why this is only for the span of function calls, not the entire `impl` block.
619 let call_drop = quote_spanned! { pinned_drop =>
620 ::pin_project::#private::PinnedDrop::drop(pinned_self)
621 };
622
623 quote! {
624 #[allow(single_use_lifetimes)]
625 impl #impl_generics ::core::ops::Drop for #ident #ty_generics #where_clause {
626 fn drop(&mut self) {
627 // Safety - we're in 'drop', so we know that 'self' will
628 // never move again.
629 let pinned_self = unsafe { ::core::pin::Pin::new_unchecked(self) };
630 // We call `pinned_drop` only once. Since `PinnedDrop::drop`
631 // is an unsafe function and a private API, it is never called again in safe
632 // code *unless the user uses a maliciously crafted macro*.
633 unsafe {
634 #call_drop;
635 }
636 }
637 }
638 }
639 } else {
640 // If the user does not provide a pinned_drop impl,
641 // we need to ensure that they don't provide a `Drop` impl of their
642 // own.
643 // Based on https://github.com/upsuper/assert-impl/blob/f503255b292ab0ba8d085b657f4065403cfa46eb/src/lib.rs#L80-L87
644 //
645 // We create a new identifier for each struct, so that the traits
646 // for different types do not conflict with each other.
647 //
648 // Another approach would be to provide an empty Drop impl,
649 // which would conflict with a user-provided Drop impl.
650 // However, this would trigger the compiler's special handling
651 // of Drop types (e.g. fields cannot be moved out of a Drop type).
652 // This approach prevents the creation of needless Drop impls,
653 // giving users more flexibility.
654 let trait_ident = format_ident!("{}MustNotImplDrop", ident);
655
656 quote! {
657 // There are two possible cases:
658 // 1. The user type does not implement Drop. In this case,
659 // the first blanked impl will not apply to it. This code
660 // will compile, as there is only one impl of MustNotImplDrop for the user type
661 // 2. The user type does impl Drop. This will make the blanket impl applicable,
662 // which will then conflict with the explicit MustNotImplDrop impl below.
663 // This will result in a compilation error, which is exactly what we want.
664 trait #trait_ident {}
665 #[allow(clippy::drop_bounds)]
666 impl<T: ::core::ops::Drop> #trait_ident for T {}
667 #[allow(single_use_lifetimes)]
668 impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {}
669
670 // A dummy impl of `PinnedDrop`, to ensure that the user cannot implement it.
671 // Since the user did not pass `PinnedDrop` to `#[pin_project]`, any `PinnedDrop`
672 // impl will not actually be called. Unfortunately, we can't detect this situation
673 // directly from either the `#[pin_project]` or `#[pinned_drop]` attributes, since
674 // we don't know what other attirbutes/impl may exist.
675 //
676 // To ensure that users don't accidentally write a non-functional `PinnedDrop`
677 // impls, we emit one ourselves. If the user ends up writing a `PinnedDrop` impl,
678 // they'll get a "conflicting implementations of trait" error when coherence
679 // checks are run
680 #[allow(single_use_lifetimes)]
681 impl #impl_generics ::pin_project::#private::PinnedDrop for #ident #ty_generics #where_clause {
682 unsafe fn drop(self: ::core::pin::Pin<&mut Self>) {}
683 }
684 }
685 }
686 }
687
688 /// Creates an implementation of the projection method.
make_proj_impl(&self, proj_body: &TokenStream, proj_ref_body: &TokenStream) -> TokenStream689 fn make_proj_impl(&self, proj_body: &TokenStream, proj_ref_body: &TokenStream) -> TokenStream {
690 let vis = &self.proj.vis;
691 let lifetime = &self.proj.lifetime;
692 let orig_ident = &self.orig.ident;
693 let proj_ident = &self.proj.mut_ident;
694 let proj_ref_ident = &self.proj.ref_ident;
695
696 let proj_ty_generics = self.proj.generics.split_for_impl().1;
697 let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl();
698
699 quote! {
700 impl #impl_generics #orig_ident #ty_generics #where_clause {
701 #vis fn project<#lifetime>(
702 self: ::core::pin::Pin<&#lifetime mut Self>,
703 ) -> #proj_ident #proj_ty_generics {
704 unsafe {
705 #proj_body
706 }
707 }
708 #vis fn project_ref<#lifetime>(
709 self: ::core::pin::Pin<&#lifetime Self>,
710 ) -> #proj_ref_ident #proj_ty_generics {
711 unsafe {
712 #proj_ref_body
713 }
714 }
715 }
716 }
717 }
718
ensure_not_packed(&self, fields: &Fields) -> Result<TokenStream>719 fn ensure_not_packed(&self, fields: &Fields) -> Result<TokenStream> {
720 for meta in self.orig.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
721 if let Meta::List(l) = meta {
722 if l.path.is_ident("repr") {
723 for repr in l.nested.iter() {
724 match repr {
725 NestedMeta::Meta(Meta::Path(path))
726 | NestedMeta::Meta(Meta::List(MetaList { path, .. }))
727 if path.is_ident("packed") =>
728 {
729 return Err(error!(
730 repr,
731 "#[pin_project] attribute may not be used on #[repr(packed)] types"
732 ));
733 }
734 _ => {}
735 }
736 }
737 }
738 }
739 }
740
741 // As proc-macro-derive can't rewrite the structure definition,
742 // it's probably no longer necessary, but it keeps it for now.
743
744 // Workaround for https://github.com/taiki-e/pin-project/issues/32
745 // Through the tricky use of proc macros, it's possible to bypass
746 // the above check for the 'repr' attribute.
747 // To ensure that it's impossible to use pin projections on a #[repr(packed)]
748 // struct, we generate code like this:
749 //
750 // #[deny(safe_packed_borrows)]
751 // fn enforce_not_packed_for_MyStruct(val: &MyStruct) {
752 // let _field1 = &val.field1;
753 // let _field2 = &val.field2;
754 // ...
755 // let _fieldn = &val.fieldn;
756 // }
757 //
758 // Taking a reference to a packed field is unsafe, and applying
759 // #[deny(safe_packed_borrows)] makes sure that doing this without
760 // an 'unsafe' block (which we deliberately do not generate)
761 // is a hard error.
762 //
763 // If the struct ends up having #[repr(packed)] applied somehow,
764 // this will generate an (unfriendly) error message. Under all reasonable
765 // circumstances, we'll detect the #[repr(packed)] attribute, and generate
766 // a much nicer error above.
767 //
768 // There is one exception: If the type of a struct field has an alignment of 1
769 // (e.g. u8), it is always safe to take a reference to it, even if the struct
770 // is #[repr(packed)]. If the struct is composed entirely of types of alignment 1,
771 // our generated method will not trigger an error if the struct is #[repr(packed)]
772 //
773 // Fortunately, this should have no observable consequence - #[repr(packed)]
774 // is essentially a no-op on such a type. Nevertheless, we include a test
775 // to ensure that the compiler doesn't ever try to copy the fields on
776 // such a struct when trying to drop it - which is reason we prevent
777 // #[repr(packed)] in the first place.
778 //
779 // See also https://github.com/taiki-e/pin-project/pull/34.
780 let mut field_refs = vec![];
781 match fields {
782 Fields::Named(FieldsNamed { named, .. }) => {
783 for Field { ident, .. } in named {
784 field_refs.push(quote! {
785 &val.#ident;
786 });
787 }
788 }
789 Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
790 for (index, _) in unnamed.iter().enumerate() {
791 let index = Index::from(index);
792 field_refs.push(quote! {
793 &val.#index;
794 });
795 }
796 }
797 Fields::Unit => {}
798 }
799
800 let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl();
801
802 let struct_name = &self.orig.ident;
803 let method_name = format_ident!("__pin_project_assert_not_repr_packed_{}", self.orig.ident);
804 Ok(quote! {
805 #[allow(single_use_lifetimes)]
806 #[allow(non_snake_case)]
807 #[deny(safe_packed_borrows)]
808 fn #method_name #impl_generics (val: &#struct_name #ty_generics) #where_clause {
809 #(#field_refs)*
810 }
811 })
812 }
813 }
814