Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Immovable types prototype where the Move trait is builtin #44917

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ impl !Type for Trait
Example:

```rust
#![feature(optin_builtin_traits)]
#![feature(optin_builtin_traits, immovable_types)]

auto trait Valid {}
use std::marker::Move;

auto trait Valid: ?Move {}

struct True;
struct False;
Expand Down
33 changes: 32 additions & 1 deletion src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ use core::cmp::Ordering;
use core::fmt;
use core::hash::{self, Hash, Hasher};
use core::iter::FusedIterator;
#[cfg(not(stage0))]
use core::marker::Move;
use core::marker::{self, Unsize};
use core::mem;
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
Expand Down Expand Up @@ -103,13 +105,21 @@ pub struct ExchangeHeapSingleton {
_force_singleton: (),
}

/// docs
#[cfg(stage0)]
#[lang = "owned_box"]
#[fundamental]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Box<T: ?Sized>(Unique<T>);

/// A pointer type for heap allocation.
///
/// See the [module-level documentation](../../std/boxed/index.html) for more.
#[cfg(not(stage0))]
#[lang = "owned_box"]
#[fundamental]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Box<T: ?Sized>(Unique<T>);
pub struct Box<T: ?Sized+?Move>(Unique<T>);

/// `IntermediateBox` represents uninitialized backing storage for `Box`.
///
Expand Down Expand Up @@ -377,12 +387,21 @@ impl<T: ?Sized> Box<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
unsafe impl<#[may_dangle] T: ?Sized> Drop for Box<T> {
fn drop(&mut self) {
// FIXME: Do nothing, drop is currently performed by compiler.
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
unsafe impl<#[may_dangle] T: ?Sized+?Move> Drop for Box<T> {
fn drop(&mut self) {
// FIXME: Do nothing, drop is currently performed by compiler.
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Default> Default for Box<T> {
/// Creates a `Box<T>`, with the `Default` value for T.
Expand Down Expand Up @@ -752,6 +771,18 @@ impl<I: FusedIterator + ?Sized> FusedIterator for Box<I> {}
/// }
/// }
/// ```
#[cfg(not(stage0))]
#[rustc_paren_sugar]
#[unstable(feature = "fnbox",
reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")]
pub trait FnBox<A> {
type Output: ?Move;

fn call_box(self: Box<Self>, args: A) -> Self::Output;
}

/// docs
#[cfg(stage0)]
#[rustc_paren_sugar]
#[unstable(feature = "fnbox",
reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")]
Expand Down
1 change: 1 addition & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
#![feature(slice_rsplit)]
#![feature(specialization)]
#![feature(staged_api)]
#![cfg_attr(not(stage0), feature(immovable_types))]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(unboxed_closures)]
Expand Down
34 changes: 34 additions & 0 deletions src/libcore/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ use marker::Unsize;
use mem;
use ops::{Deref, DerefMut, CoerceUnsized};
use ptr;
#[cfg(not(stage0))]
use marker::Move;

/// A mutable memory location.
///
Expand Down Expand Up @@ -1292,3 +1294,35 @@ fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) {
let _: Cell<&Send> = b;
let _: RefCell<&Send> = c;
}

/// A cell that is always movable, even if the interior type is immovable.
Copy link
Contributor

@arielb1 arielb1 Oct 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't a normal Cell take T: ?Move? I suppose that wouldn't work because we need a lang-item.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth checking the performance effects if you add sized_constraint-style shortcutting for arbitrary OIBITs. You should be able to recurse as long as there's no impl available.

That will probably require an additional check that no where-clauses are interfering so that Option<T>: Move where-clauses work (today, a (T, T): Sized bound don't actually work), but that might be better performance-wise than going through selection for every single field.

/// This prevents pointers to the inner type which means it can never be observed.
#[cfg(not(stage0))]
#[unstable(feature = "immovable_types", issue = "0")]
#[lang = "movable_cell"]
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct MovableCell<T: ?Move> {
value: T,
}

#[unstable(feature = "immovable_types", issue = "0")]
#[cfg(not(stage0))]
impl<T: ?Move> MovableCell<T> {
/// Creates a new MovableCell.
pub const fn new(value: T) -> Self {
MovableCell {
value: value,
}
}

/// Extracts the inner value.
pub fn into_inner(self) -> T {
self.value
}

/// Replaces the inner value.
pub fn replace(&mut self, new_value: T) -> T {
mem::replace(self, MovableCell::new(new_value)).into_inner()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing newline

15 changes: 14 additions & 1 deletion src/libcore/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

#![stable(feature = "rust1", since = "1.0.0")]

#[cfg(not(stage0))]
use marker::Move;

/// A trait for giving a type a useful default value.
///
/// Sometimes, you want to fall back to some kind of default value, and
Expand Down Expand Up @@ -90,8 +93,9 @@
/// bar: f32,
/// }
/// ```
#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Default: Sized {
pub trait Default: Sized + ?Move {
/// Returns the "default value" for a type.
///
/// Default values are often some kind of initial value, identity value, or anything else that
Expand Down Expand Up @@ -125,6 +129,15 @@ pub trait Default: Sized {
fn default() -> Self;
}

/// docs
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Default: Sized {
/// docs
#[stable(feature = "rust1", since = "1.0.0")]
fn default() -> Self;
}

macro_rules! default_impl {
($t:ty, $v:expr, $doc:tt) => {
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
77 changes: 77 additions & 0 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ use hash::Hasher;
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(stage0, lang = "send")]
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
#[cfg(not(stage0))]
pub unsafe trait Send: ?Move {
// empty.
}

/// docs
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "send"]
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
#[cfg(stage0)]
pub unsafe trait Send {
// empty.
}
Expand All @@ -50,11 +60,20 @@ pub unsafe trait Send {
#[allow(auto_impl)]
unsafe impl Send for .. { }

#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Send for *const T { }
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Send for *mut T { }

#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized+?Move> !Send for *const T { }
#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized+?Move> !Send for *mut T { }

/// Types with a constant size known at compile time.
///
/// All type parameters have an implicit bound of `Sized`. The special syntax
Expand Down Expand Up @@ -92,10 +111,37 @@ impl<T: ?Sized> !Send for *mut T { }
#[lang = "sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[cfg(not(stage0))]
pub trait Sized: ?Move {
// Empty.
}

/// docs
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[cfg(stage0)]
pub trait Sized {
// Empty.
}

/// Types that can be moved after being borrowed.
#[cfg(not(stage0))]
#[lang = "move"]
#[unstable(feature = "immovable_types", issue = "0")]
pub unsafe trait Move: ?Move {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird: do you have to have ?Move constraint on this trait?

Just curious, since I noticed that trait Sized does not have an analogous ?Sized bound...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto traits cannot have supertraits because that is unsound. Also we do not want Move to require Move. That would probably result in interesting things happening.

// Empty.
}

/// A zero-sized struct which is immovable.
#[cfg(not(stage0))]
#[lang = "immovable"]
#[unstable(feature = "immovable_types", issue = "0")]
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct Immovable;

/// Types that can be "unsized" to a dynamically-sized type.
///
/// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and
Expand Down Expand Up @@ -346,6 +392,16 @@ pub trait Copy : Clone {
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sync"]
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
#[cfg(not(stage0))]
pub unsafe trait Sync: ?Move {
// Empty
}

/// docs
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sync"]
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
#[cfg(stage0)]
pub unsafe trait Sync {
// Empty
}
Expand All @@ -355,11 +411,20 @@ pub unsafe trait Sync {
#[allow(auto_impl)]
unsafe impl Sync for .. { }

#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Sync for *const T { }
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Sync for *mut T { }

#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized+?Move> !Sync for *const T { }
#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized+?Move> !Sync for *mut T { }

macro_rules! impls{
($t: ident) => (
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -546,6 +611,13 @@ macro_rules! impls{
/// as not to indicate ownership.
///
/// [drop check]: ../../nomicon/dropck.html
#[cfg(not(stage0))]
#[lang = "phantom_data"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PhantomData<T:?Sized+?Move>;

/// docs
#[cfg(stage0)]
#[lang = "phantom_data"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PhantomData<T:?Sized>;
Expand All @@ -564,6 +636,11 @@ mod impls {
/// This affects, for example, whether a `static` of that type is
/// placed in read-only static memory or writable static memory.
#[lang = "freeze"]
#[cfg(not(stage0))]
unsafe trait Freeze: ?Move {}

#[lang = "freeze"]
#[cfg(stage0)]
unsafe trait Freeze {}

#[allow(unknown_lints)]
Expand Down
12 changes: 12 additions & 0 deletions src/libcore/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
issue = "27730")]

use ops::CoerceUnsized;
#[cfg(not(stage0))]
use marker::Move;

/// Unsafe trait to indicate what types are usable with the NonZero struct
pub unsafe trait Zeroable {
Expand All @@ -24,6 +26,7 @@ pub unsafe trait Zeroable {
macro_rules! impl_zeroable_for_pointer_types {
( $( $Ptr: ty )+ ) => {
$(
#[cfg(stage0)]
/// For fat pointers to be considered "zero", only the "data" part needs to be null.
unsafe impl<T: ?Sized> Zeroable for $Ptr {
#[inline]
Expand All @@ -32,6 +35,15 @@ macro_rules! impl_zeroable_for_pointer_types {
(*self as *mut u8).is_null()
}
}
#[cfg(not(stage0))]
/// For fat pointers to be considered "zero", only the "data" part needs to be null.
unsafe impl<T: ?Sized+?Move> Zeroable for $Ptr {
#[inline]
fn is_zero(&self) -> bool {
// Cast because `is_null` is only available on thin pointers
(*self as *mut u8).is_null()
}
}
)+
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/libcore/ops/deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(not(stage0))]
use marker::Move;

/// Used for immutable dereferencing operations, like `*v`.
///
/// In addition to being used for explicit dereferencing operations with the
Expand Down Expand Up @@ -72,7 +75,12 @@
pub trait Deref {
/// The resulting type after dereferencing.
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
type Target: ?Sized;
/// The resulting type after dereferencing
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
type Target: ?Sized+?Move;

/// Dereferences the value.
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
Loading