Skip to content

Commit

Permalink
Rollup merge of rust-lang#76655 - CDirkx:const-pin, r=ecstatic-morse
Browse files Browse the repository at this point in the history
Make some methods of `Pin` unstable const

Make the following methods unstable const under the `const_pin` feature:
- `new`
- `new_unchecked`
- `into_inner`
- `into_inner_unchecked`
- `get_ref`
- `into_ref`
- `get_mut`
- `get_unchecked_mut`

Of these, `into_inner` and `into_inner_unchecked` require the unstable `const_precise_live_drops`.

Also adds tests for these methods in a const context.

Tracking issue: rust-lang#76654

r? @ecstatic-morse
  • Loading branch information
ecstatic-morse authored Sep 22, 2020
2 parents 30f1bab + e3c6e46 commit 537ede4
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 16 deletions.
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
#![feature(const_int_pow)]
#![feature(constctlz)]
#![feature(const_panic)]
#![feature(const_pin)]
#![feature(const_fn_union)]
#![feature(const_generics)]
#![feature(const_option)]
Expand Down
40 changes: 24 additions & 16 deletions library/core/src/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,9 +471,10 @@ impl<P: Deref<Target: Unpin>> Pin<P> {
///
/// Unlike `Pin::new_unchecked`, this method is safe because the pointer
/// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees.
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
pub fn new(pointer: P) -> Pin<P> {
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
#[stable(feature = "pin", since = "1.33.0")]
pub const fn new(pointer: P) -> Pin<P> {
// SAFETY: the value pointed to is `Unpin`, and so has no requirements
// around pinning.
unsafe { Pin::new_unchecked(pointer) }
Expand All @@ -483,9 +484,10 @@ impl<P: Deref<Target: Unpin>> Pin<P> {
///
/// This requires that the data inside this `Pin` is [`Unpin`] so that we
/// can ignore the pinning invariants when unwrapping it.
#[stable(feature = "pin_into_inner", since = "1.39.0")]
#[inline(always)]
pub fn into_inner(pin: Pin<P>) -> P {
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
#[stable(feature = "pin_into_inner", since = "1.39.0")]
pub const fn into_inner(pin: Pin<P>) -> P {
pin.pointer
}
}
Expand Down Expand Up @@ -556,9 +558,10 @@ impl<P: Deref> Pin<P> {
///
/// [`mem::swap`]: crate::mem::swap
#[lang = "new_unchecked"]
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
pub unsafe fn new_unchecked(pointer: P) -> Pin<P> {
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
#[stable(feature = "pin", since = "1.33.0")]
pub const unsafe fn new_unchecked(pointer: P) -> Pin<P> {
Pin { pointer }
}

Expand Down Expand Up @@ -589,9 +592,10 @@ impl<P: Deref> Pin<P> {
///
/// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used
/// instead.
#[stable(feature = "pin_into_inner", since = "1.39.0")]
#[inline(always)]
pub unsafe fn into_inner_unchecked(pin: Pin<P>) -> P {
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
#[stable(feature = "pin_into_inner", since = "1.39.0")]
pub const unsafe fn into_inner_unchecked(pin: Pin<P>) -> P {
pin.pointer
}
}
Expand Down Expand Up @@ -693,18 +697,20 @@ impl<'a, T: ?Sized> Pin<&'a T> {
/// with the same lifetime as the original `Pin`.
///
/// ["pinning projections"]: self#projections-and-structural-pinning
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
pub fn get_ref(self) -> &'a T {
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
#[stable(feature = "pin", since = "1.33.0")]
pub const fn get_ref(self) -> &'a T {
self.pointer
}
}

impl<'a, T: ?Sized> Pin<&'a mut T> {
/// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
pub fn into_ref(self) -> Pin<&'a T> {
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
#[stable(feature = "pin", since = "1.33.0")]
pub const fn into_ref(self) -> Pin<&'a T> {
Pin { pointer: self.pointer }
}

Expand All @@ -717,9 +723,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> {
/// that lives for as long as the borrow of the `Pin`, not the lifetime of
/// the `Pin` itself. This method allows turning the `Pin` into a reference
/// with the same lifetime as the original `Pin`.
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
pub fn get_mut(self) -> &'a mut T
#[stable(feature = "pin", since = "1.33.0")]
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
pub const fn get_mut(self) -> &'a mut T
where
T: Unpin,
{
Expand All @@ -736,9 +743,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> {
///
/// If the underlying data is `Unpin`, `Pin::get_mut` should be used
/// instead.
#[stable(feature = "pin", since = "1.33.0")]
#[inline(always)]
pub unsafe fn get_unchecked_mut(self) -> &'a mut T {
#[stable(feature = "pin", since = "1.33.0")]
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
pub const unsafe fn get_unchecked_mut(self) -> &'a mut T {
self.pointer
}

Expand Down
3 changes: 3 additions & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
#![feature(iter_order_by)]
#![feature(cmp_min_max_by)]
#![feature(iter_map_while)]
#![feature(const_mut_refs)]
#![feature(const_pin)]
#![feature(const_slice_from_raw_parts)]
#![feature(const_raw_ptr_deref)]
#![feature(never_type)]
Expand Down Expand Up @@ -79,6 +81,7 @@ mod num;
mod ops;
mod option;
mod pattern;
mod pin;
mod ptr;
mod result;
mod slice;
Expand Down
31 changes: 31 additions & 0 deletions library/core/tests/pin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use core::pin::Pin;

#[test]
fn pin_const() {
// test that the methods of `Pin` are usable in a const context

const POINTER: &'static usize = &2;

const PINNED: Pin<&'static usize> = Pin::new(POINTER);
const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) };
assert_eq!(PINNED_UNCHECKED, PINNED);

const INNER: &'static usize = Pin::into_inner(PINNED);
assert_eq!(INNER, POINTER);

const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) };
assert_eq!(INNER_UNCHECKED, POINTER);

const REF: &'static usize = PINNED.get_ref();
assert_eq!(REF, POINTER);

// Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context.
// A const fn is used because `&mut` is not (yet) usable in constants.
const fn pin_mut_const() {
let _ = Pin::new(&mut 2).into_ref();
let _ = Pin::new(&mut 2).get_mut();
let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() };
}

pin_mut_const();
}

0 comments on commit 537ede4

Please sign in to comment.