|
| 1 | +// check-pass |
| 2 | +// known-bug: #85099 |
| 3 | + |
| 4 | +// Should fail. Can coerce `Pin<T>` into `Pin<U>` where |
| 5 | +// `T: Deref<Target: Unpin>` and `U: Deref<Target: !Unpin>`, using the |
| 6 | +// `CoerceUnsized` impl on `Pin` and an unorthodox `DerefMut` impl for |
| 7 | +// `Pin<&_>`. |
| 8 | + |
| 9 | +// This should not be allowed, since one can unpin `T::Target` (since it is |
| 10 | +// `Unpin`) to gain unpinned access to the previously pinned `U::Target` (which |
| 11 | +// is `!Unpin`) and then move it. |
| 12 | + |
| 13 | +use std::{ |
| 14 | + cell::{RefCell, RefMut}, |
| 15 | + future::Future, |
| 16 | + ops::DerefMut, |
| 17 | + pin::Pin, |
| 18 | +}; |
| 19 | + |
| 20 | +struct SomeLocalStruct<'a, Fut>(&'a RefCell<Fut>); |
| 21 | + |
| 22 | +trait SomeTrait<'a, Fut> { |
| 23 | + #[allow(clippy::mut_from_ref)] |
| 24 | + fn deref_helper(&self) -> &mut (dyn SomeTrait<'a, Fut> + 'a) { |
| 25 | + unimplemented!() |
| 26 | + } |
| 27 | + fn downcast(self: Pin<&mut Self>) -> Pin<&mut Fut> { |
| 28 | + unimplemented!() |
| 29 | + } |
| 30 | +} |
| 31 | + |
| 32 | +impl<'a, Fut: Future<Output = ()>> SomeTrait<'a, Fut> for SomeLocalStruct<'a, Fut> { |
| 33 | + fn deref_helper(&self) -> &mut (dyn SomeTrait<'a, Fut> + 'a) { |
| 34 | + let x = Box::new(self.0.borrow_mut()); |
| 35 | + let x: &'a mut RefMut<'a, Fut> = Box::leak(x); |
| 36 | + &mut **x |
| 37 | + } |
| 38 | +} |
| 39 | +impl<'a, Fut: Future<Output = ()>> SomeTrait<'a, Fut> for Fut { |
| 40 | + fn downcast(self: Pin<&mut Self>) -> Pin<&mut Fut> { |
| 41 | + self |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { |
| 46 | + fn deref_mut<'c>( |
| 47 | + self: &'c mut Pin<&'b dyn SomeTrait<'a, Fut>>, |
| 48 | + ) -> &'c mut (dyn SomeTrait<'a, Fut> + 'b) { |
| 49 | + self.deref_helper() |
| 50 | + } |
| 51 | +} |
| 52 | + |
| 53 | +// obviously a "working" function with this signature is problematic |
| 54 | +pub fn unsound_pin<Fut: Future<Output = ()>>( |
| 55 | + fut: Fut, |
| 56 | + callback: impl FnOnce(Pin<&mut Fut>), |
| 57 | +) -> Fut { |
| 58 | + let cell = RefCell::new(fut); |
| 59 | + let s: &SomeLocalStruct<'_, Fut> = &SomeLocalStruct(&cell); |
| 60 | + let p: Pin<Pin<&SomeLocalStruct<'_, Fut>>> = Pin::new(Pin::new(s)); |
| 61 | + let mut p: Pin<Pin<&dyn SomeTrait<'_, Fut>>> = p; |
| 62 | + let r: Pin<&mut dyn SomeTrait<'_, Fut>> = p.as_mut(); |
| 63 | + let f: Pin<&mut Fut> = r.downcast(); |
| 64 | + callback(f); |
| 65 | + cell.into_inner() |
| 66 | +} |
| 67 | + |
| 68 | +fn main() {} |
0 commit comments