Skip to content

Commit 8f93fc9

Browse files
committed
prevent deref coercions in pin!
1 parent e0f239a commit 8f93fc9

3 files changed

Lines changed: 23 additions & 2 deletions

File tree

library/core/src/pin.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2034,6 +2034,13 @@ pub macro pin($value:expr $(,)?) {
20342034
{
20352035
super let mut pinned = $value;
20362036
// SAFETY: The value is pinned: it is the local above which cannot be named outside this macro.
2037-
unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) }
2037+
// HACK: We assign to `pinned_ref` to limit type inference. If a type annotation leads to an
2038+
// expected result type for `Pin::new_unchecked`, its argument will be a coercion site. If the
2039+
// argument is dereferenced by a coercion, the pinning invariant will be broken, leading to
2040+
// unsoundness; see <https://github.com/rust-lang/rust/issues/153438>. By separating out an
2041+
// assignment like this, we won't have an expectation on `pinned_ref`'s type when type-checking
2042+
// it, meaning we shouldn't see deref coercion.
2043+
let pinned_ref = unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) };
2044+
pinned_ref
20382045
}
20392046
}

tests/ui/pin/dont-deref-coerce-pinned-value.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
//! expectation on `pin!`'s result, make sure we don't deref-coerce the argument to
33
//! `Pin::new_unchecked` to get its type to match up. That violates the pinning invariant, leading
44
//! to unsoundness!
5-
//@ check-pass
65
76
use std::pin::{Pin, pin};
87

98
fn wrong_pin<T>(data: &mut T, callback: impl FnOnce(Pin<&mut T>)) {
109
callback(pin!(data));
10+
//~^ ERROR: mismatched types
1111
}
1212

1313
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/dont-deref-coerce-pinned-value.rs:9:14
3+
|
4+
LL | fn wrong_pin<T>(data: &mut T, callback: impl FnOnce(Pin<&mut T>)) {
5+
| - expected this type parameter
6+
LL | callback(pin!(data));
7+
| ^^^^^^^^^^ expected `Pin<&mut T>`, found `Pin<&mut &mut T>`
8+
|
9+
= note: expected struct `Pin<&mut _>`
10+
found struct `Pin<&mut &mut _>`
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)