@@ -543,7 +543,7 @@ impl<P: Deref> Pin<P> {
543543///         let p: Pin<&mut T> = Pin::new_unchecked(&mut a); 
544544///         // This should mean the pointee `a` can never move again. 
545545///     } 
546- ///     mem::swap(&mut a, &mut b); 
546+ ///     mem::swap(&mut a, &mut b); // Potential UB down the road ⚠️  
547547///     // The address of `a` changed to `b`'s stack slot, so `a` got moved even 
548548///     // though we have previously pinned it! We have violated the pinning API contract. 
549549/// } 
@@ -563,13 +563,66 @@ impl<P: Deref> Pin<P> {
563563///         // This should mean the pointee can never move again. 
564564///     } 
565565///     drop(pinned); 
566- ///     let content = Rc::get_mut(&mut x).unwrap(); 
566+ ///     let content = Rc::get_mut(&mut x).unwrap(); // Potential UB down the road ⚠️  
567567///     // Now, if `x` was the only reference, we have a mutable reference to 
568568///     // data that we pinned above, which we could use to move it as we have 
569569///     // seen in the previous example. We have violated the pinning API contract. 
570570///  } 
571571///  ``` 
572572/// 
573+ /// ## Pinning of closure captures 
574+ /// 
575+ /// Particular care is required when using `Pin::new_unchecked` in a closure: 
576+ /// `Pin::new_unchecked(&mut var)` where `var` is a by-value (moved) closure capture 
577+ /// implicitly makes the promise that the closure itself is pinned, and that *all* uses 
578+ /// of this closure capture respect that pinning. 
579+ /// ``` 
580+ /// use std::pin::Pin; 
581+ /// use std::task::Context; 
582+ /// use std::future::Future; 
583+ /// 
584+ /// fn move_pinned_closure(mut x: impl Future, cx: &mut Context<'_>) { 
585+ ///     // Create a closure that moves `x`, and then internally uses it in a pinned way. 
586+ ///     let mut closure = move || unsafe { 
587+ ///         let _ignore = Pin::new_unchecked(&mut x).poll(cx); 
588+ ///     }; 
589+ ///     // Call the closure, so the future can assume it has been pinned. 
590+ ///     closure(); 
591+ ///     // Move the closure somewhere else. This also moves `x`! 
592+ ///     let mut moved = closure; 
593+ ///     // Calling it again means we polled the future from two different locations, 
594+ ///     // violating the pinning API contract. 
595+ ///     moved(); // Potential UB ⚠️ 
596+ /// } 
597+ /// ``` 
598+ /// When passing a closure to another API, it might be moving the closure any time, so 
599+ /// `Pin::new_unchecked` on closure captures may only be used if the API explicitly documents 
600+ /// that the closure is pinned. 
601+ /// 
602+ /// The better alternative is to avoid all that trouble and do the pinning in the outer function 
603+ /// instead (here using the unstable `pin` macro): 
604+ /// ``` 
605+ /// #![feature(pin_macro)] 
606+ /// use std::pin::pin; 
607+ /// use std::task::Context; 
608+ /// use std::future::Future; 
609+ /// 
610+ /// fn move_pinned_closure(mut x: impl Future, cx: &mut Context<'_>) { 
611+ ///     let mut x = pin!(x); 
612+ ///     // Create a closure that captures `x: Pin<&mut _>`, which is safe to move. 
613+ ///     let mut closure = move || { 
614+ ///         let _ignore = x.as_mut().poll(cx); 
615+ ///     }; 
616+ ///     // Call the closure, so the future can assume it has been pinned. 
617+ ///     closure(); 
618+ ///     // Move the closure somewhere else. 
619+ ///     let mut moved = closure; 
620+ ///     // Calling it again here is fine (except that we might be polling a future that already 
621+ ///     // returned `Poll::Ready`, but that is a separate problem). 
622+ ///     moved(); 
623+ /// } 
624+ /// ``` 
625+ /// 
573626/// [`mem::swap`]: crate::mem::swap 
574627#[ lang = "new_unchecked" ]  
575628    #[ inline( always) ]  
0 commit comments