"For example, calling Pin::new_unchecked on an &'a mut T is unsafe because while you are able to pin it for the given lifetime 'a, you have no control over whether it is kept pinned once 'a ends, and therefore cannot uphold the guarantee that a value, once pinned, remains pinned until it is dropped:"
use std::mem;
use std::pin::Pin;
fn move_pinned_ref<T>(mut a: T, mut b: T) {
unsafe {
let p: Pin<&mut T> = Pin::new_unchecked(&mut a);
// This should mean the pointee `a` can never move again.
}
mem::swap(&mut a, &mut b); // Potential UB down the road ⚠️
// The address of `a` changed to `b`'s stack slot, so `a` got moved even
// though we have previously pinned it! We have violated the pinning API contract.
}
This is from rust's official documentation of Pin::new_unchecked
https://doc.rust-lang.org/std/pin/struct.Pin.html#method.new_unchecked. So why is calling new_unchecked
on shared reference &T
safe? I can still move T itself afterwards. For example, in the following code, I can simply change the sample code to using shared reference. Why is this safe?
fn move_pinned<T>(mut var: T, mut b: T) {
unsafe {
let p: Pin<&T> = Pin::new_unchecked(&var);
}
mem::swap(&mut var, &mut b);
}