Skip to content

Commit

Permalink
PinCoerceUnsized trait into core
Browse files Browse the repository at this point in the history
  • Loading branch information
dingxiangfei2009 committed Jul 15, 2024
1 parent d3dd34a commit ea678b7
Show file tree
Hide file tree
Showing 12 changed files with 170 additions and 4 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ symbols! {
Path,
PathBuf,
Pending,
PinCoerceUnsized,
Pointer,
Poll,
ProcMacro,
Expand Down
5 changes: 4 additions & 1 deletion library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ use core::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
use core::ops::{
CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver,
};
use core::pin::Pin;
use core::pin::{Pin, PinCoerceUnsized};
use core::ptr::{self, addr_of_mut, NonNull, Unique};
use core::slice;
use core::task::{Context, Poll};
Expand Down Expand Up @@ -2646,3 +2646,6 @@ impl<T: core::error::Error> core::error::Error for Box<T> {
core::error::Error::provide(&**self, request);
}
}

#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {}
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
#![feature(maybe_uninit_uninit_array_transpose)]
#![feature(panic_internals)]
#![feature(pattern)]
#![feature(pin_coerce_unsized_trait)]
#![feature(ptr_internals)]
#![feature(ptr_metadata)]
#![feature(ptr_sub_ptr)]
Expand Down
7 changes: 7 additions & 0 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Rece
use core::panic::{RefUnwindSafe, UnwindSafe};
#[cfg(not(no_global_oom_handling))]
use core::pin::Pin;
use core::pin::PinCoerceUnsized;
use core::ptr::{self, drop_in_place, NonNull};
#[cfg(not(no_global_oom_handling))]
use core::slice::from_raw_parts_mut;
Expand Down Expand Up @@ -2181,6 +2182,9 @@ impl<T: ?Sized, A: Allocator> Deref for Rc<T, A> {
}
}

#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Rc<T, A> {}

#[unstable(feature = "deref_pure_trait", issue = "87121")]
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Rc<T, A> {}

Expand Down Expand Up @@ -3696,6 +3700,9 @@ impl<T: ?Sized, A: Allocator> Deref for UniqueRc<T, A> {
}
}

#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
unsafe impl<T: ?Sized> PinCoerceUnsized for UniqueRc<T> {}

#[unstable(feature = "unique_rc_arc", issue = "112566")]
impl<T: ?Sized, A: Allocator> DerefMut for UniqueRc<T, A> {
fn deref_mut(&mut self) -> &mut T {
Expand Down
5 changes: 4 additions & 1 deletion library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use core::marker::{PhantomData, Unsize};
use core::mem::{self, align_of_val_raw};
use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::pin::Pin;
use core::pin::{Pin, PinCoerceUnsized};
use core::ptr::{self, NonNull};
#[cfg(not(no_global_oom_handling))]
use core::slice::from_raw_parts_mut;
Expand Down Expand Up @@ -2147,6 +2147,9 @@ impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
}
}

#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Arc<T, A> {}

#[unstable(feature = "deref_pure_trait", issue = "87121")]
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {}

Expand Down
14 changes: 14 additions & 0 deletions library/alloc/tests/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,17 @@ fn make_mut_unsized() {
assert_eq!(*data, [11, 21, 31]);
assert_eq!(*other_data, [110, 20, 30]);
}

#[allow(unused)]
mod pin_coerce_unsized {
use alloc::sync::Arc;
use core::pin::Pin;

pub trait MyTrait {}
impl MyTrait for String {}

// Pin coercion should work for Arc
pub fn pin_arc(arg: Pin<Arc<String>>) -> Pin<Arc<dyn MyTrait>> {
arg
}
}
37 changes: 37 additions & 0 deletions library/alloc/tests/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,40 @@ unsafe impl Allocator for ConstAllocator {
self
}
}

#[allow(unused)]
mod pin_coerce_unsized {
use alloc::boxed::Box;
use core::pin::Pin;

trait MyTrait {
fn action(&self) -> &str;
}
impl MyTrait for String {
fn action(&self) -> &str {
&*self
}
}
struct MyStruct;
impl MyTrait for MyStruct {
fn action(&self) -> &str {
"MyStruct"
}
}

// Pin coercion should work for Box
fn pin_box<T: MyTrait + 'static>(arg: Pin<Box<T>>) -> Pin<Box<dyn MyTrait>> {
arg
}

#[test]
fn pin_coerce_unsized_box() {
let my_string = "my string";
let a_string = Box::pin(String::from(my_string));
let pin_box_str = pin_box(a_string);
assert_eq!(pin_box_str.as_ref().action(), my_string);
let a_struct = Box::pin(MyStruct);
let pin_box_struct = pin_box(a_struct);
assert_eq!(pin_box_struct.as_ref().action(), "MyStruct");
}
}
1 change: 1 addition & 0 deletions library/alloc/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#![feature(drain_keep_rest)]
#![feature(local_waker)]
#![feature(vec_pop_if)]
#![feature(unique_rc_arc)]
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]
Expand Down
17 changes: 17 additions & 0 deletions library/alloc/tests/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,20 @@ fn weak_may_dangle() {
// `val` dropped here while still borrowed
// borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
}

#[allow(unused)]
mod pin_coerce_unsized {
use alloc::rc::{Rc, UniqueRc};
use core::pin::Pin;

pub trait MyTrait {}
impl MyTrait for String {}

// Pin coercion should work for Rc
pub fn pin_rc(arg: Pin<Rc<String>>) -> Pin<Rc<dyn MyTrait>> {
arg
}
pub fn pin_unique_rc(arg: Pin<UniqueRc<String>>) -> Pin<UniqueRc<dyn MyTrait>> {
arg
}
}
10 changes: 10 additions & 0 deletions library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ use crate::fmt::{self, Debug, Display};
use crate::marker::{PhantomData, Unsize};
use crate::mem;
use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
use crate::pin::PinCoerceUnsized;
use crate::ptr::{self, NonNull};

mod lazy;
Expand Down Expand Up @@ -2394,3 +2395,12 @@ fn assert_coerce_unsized(
let _: Cell<&dyn Send> = c;
let _: RefCell<&dyn Send> = d;
}

#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
unsafe impl<T: ?Sized> PinCoerceUnsized for UnsafeCell<T> {}

#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
unsafe impl<T: ?Sized> PinCoerceUnsized for Cell<T> {}

#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
unsafe impl<T: ?Sized> PinCoerceUnsized for RefCell<T> {}
44 changes: 42 additions & 2 deletions library/core/src/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1717,10 +1717,50 @@ impl<Ptr: fmt::Pointer> fmt::Pointer for Pin<Ptr> {
// for other reasons, though, so we just need to take care not to allow such
// impls to land in std.
#[stable(feature = "pin", since = "1.33.0")]
impl<Ptr, U> CoerceUnsized<Pin<U>> for Pin<Ptr> where Ptr: CoerceUnsized<U> {}
impl<Ptr, U> CoerceUnsized<Pin<U>> for Pin<Ptr>
where
Ptr: CoerceUnsized<U> + PinCoerceUnsized,
U: PinCoerceUnsized,
{
}

#[stable(feature = "pin", since = "1.33.0")]
impl<Ptr, U> DispatchFromDyn<Pin<U>> for Pin<Ptr>
where
Ptr: DispatchFromDyn<U> + PinCoerceUnsized,
U: PinCoerceUnsized,
{
}

#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
/// # Safety
///
/// Implementing this unsafe traits requires the guarantee that any two calls
/// to `Deref::deref` must return the same value at the same address, **even after moves
/// or unsize-coercions of `self`**, with exceptions of mutations to `self`.
///
/// Here, "same value" means that if `deref` returns a trait object, then the actual
/// concrete type behind that trait object must not change.
/// Additionally, when you unsize- coerce from `Self` to `Unsized`,
/// then if you call `deref` on `Unsized` which returns a trait object reference,
/// the underlying type of that trait object must be `<Self as Deref>::Target`.
///
/// Analogous requirements apply to other unsized types. E.g., if `deref` returns
/// `[T]`, then the length must not change. In other words, the underlying type
/// must not change from `[T; N]` to `[T; M]` with an `N` different from `M`.
///
/// If this type alos implements `DerefMut`, then the same guarantee must be upheld by
/// calls to `deref_mut`.
pub unsafe trait PinCoerceUnsized {}

#[stable(feature = "pin", since = "1.33.0")]
unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a T {}

#[stable(feature = "pin", since = "1.33.0")]
unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a mut T {}

#[stable(feature = "pin", since = "1.33.0")]
impl<Ptr, U> DispatchFromDyn<Pin<U>> for Pin<Ptr> where Ptr: DispatchFromDyn<U> {}
unsafe impl<T: PinCoerceUnsized> PinCoerceUnsized for Pin<T> {}

/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning a `value: T` locally.
///
Expand Down
32 changes: 32 additions & 0 deletions library/core/tests/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,35 @@ fn pin_const() {

pin_mut_const();
}

#[allow(unused)]
mod pin_coerce_unsized {
use core::cell::{Cell, RefCell, UnsafeCell};
use core::pin::Pin;

// These Pins should continue to compile.
// Do note that these instances of Pin types cannot be used
// meaningfully because all methods require a Deref/DerefMut
// bounds on the pointer type and Cell, RefCell and UnsafeCell
// do not implement Deref/DerefMut.
pub trait MyTrait {}
impl MyTrait for String {}

pub fn cell(arg: Pin<Cell<Box<String>>>) -> Pin<Cell<Box<dyn MyTrait>>> {
arg
}
pub fn ref_cell(arg: Pin<RefCell<Box<String>>>) -> Pin<RefCell<Box<dyn MyTrait>>> {
arg
}
pub fn unsafe_cell(arg: Pin<UnsafeCell<Box<String>>>) -> Pin<UnsafeCell<Box<dyn MyTrait>>> {
arg
}

// These sensible Pin coercions are possible.
pub fn pin_mut_ref(arg: Pin<&mut String>) -> Pin<&mut dyn MyTrait> {
arg
}
pub fn pin_ref(arg: Pin<&String>) -> Pin<&dyn MyTrait> {
arg
}
}

0 comments on commit ea678b7

Please sign in to comment.