Skip to content
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
#![feature(ptr_metadata)]
#![feature(rev_into_inner)]
#![feature(set_ptr_value)]
#![feature(share_trait)]
#![feature(sized_type_properties)]
#![feature(slice_from_ptr_range)]
#![feature(slice_index_methods)]
Expand Down
5 changes: 4 additions & 1 deletion library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ use core::any::Any;
use core::cell::{Cell, CloneFromCell};
#[cfg(not(no_global_oom_handling))]
use core::clone::TrivialClone;
use core::clone::{CloneToUninit, UseCloned};
use core::clone::{CloneToUninit, Share, UseCloned};
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::intrinsics::abort;
Expand Down Expand Up @@ -2525,6 +2525,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Rc<T, A> {
#[unstable(feature = "ergonomic_clones", issue = "132290")]
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Rc<T, A> {}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T: ?Sized, A: Allocator + Clone> Share for Rc<T, A> {}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Default> Default for Rc<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 @@ -12,7 +12,7 @@ use core::any::Any;
use core::cell::CloneFromCell;
#[cfg(not(no_global_oom_handling))]
use core::clone::TrivialClone;
use core::clone::{CloneToUninit, UseCloned};
use core::clone::{CloneToUninit, Share, UseCloned};
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::intrinsics::abort;
Expand Down Expand Up @@ -2436,6 +2436,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Arc<T, A> {
#[unstable(feature = "ergonomic_clones", issue = "132290")]
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Arc<T, A> {}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T: ?Sized, A: Allocator + Clone> Share for Arc<T, A> {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
type Target = T;
Expand Down
89 changes: 88 additions & 1 deletion library/core/src/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,90 @@ pub macro Clone($item:item) {
/* compiler built-in */
}

/// A trait for types whose [`Clone`] operation creates another alias to the same
/// logical resource or shared state.
///
/// `Share` marks types where cloning creates another handle, reference, or alias
/// to the same logical resource or shared state, rather than an independent owned
/// value. The distinction is semantic, not cost-based: implementing `Share` does
/// not merely mean that cloning is cheap, constant-time, allocation-free, or
/// convenient.
///
/// Calling [`share`](Share::share) is equivalent to calling [`clone`](Clone::clone)
/// for implementors, but communicates that the resulting value aliases the same
/// underlying resource.
///
/// Shared references, `Rc<T>`, `Arc<T>`, `Sender<T>`, and `SyncSender<T>` are
/// examples of types that can be shared this way. Types such as `Vec<T>`,
/// `String`, and `Box<T>` are not `Share` even though they implement `Clone`,
/// because cloning them creates another owned value rather than another handle
/// to the same logical resource.
///
/// # Examples
///
/// ```
/// #![feature(share_trait)]
///
/// use std::cell::Cell;
/// use std::clone::Share;
/// use std::rc::Rc;
/// use std::sync::{
/// Arc,
/// atomic::{AtomicUsize, Ordering},
/// };
///
/// let value = 1;
/// let reference = &value;
/// assert!(std::ptr::eq(reference, reference.share()));
///
/// let rc = Rc::new(Cell::new(2));
/// let shared_rc = rc.share();
/// assert!(Rc::ptr_eq(&rc, &shared_rc));
/// shared_rc.set(3);
/// assert_eq!(rc.get(), 3);
///
/// let arc = Arc::new(AtomicUsize::new(4));
/// let shared_arc = arc.share();
/// assert!(Arc::ptr_eq(&arc, &shared_arc));
/// shared_arc.store(5, Ordering::Relaxed);
/// assert_eq!(arc.load(Ordering::Relaxed), 5);
/// ```
///
/// ```
/// #![feature(share_trait)]
///
/// use std::clone::Share;
/// use std::sync::mpsc::{channel, sync_channel};
///
/// let (sender, receiver) = channel();
/// let shared_sender = sender.share();
/// sender.send(1).unwrap();
/// shared_sender.send(2).unwrap();
///
/// let mut received = [receiver.recv().unwrap(), receiver.recv().unwrap()];
/// received.sort();
/// assert_eq!(received, [1, 2]);
///
/// let (sync_sender, sync_receiver) = sync_channel(2);
/// let shared_sync_sender = sync_sender.share();
/// sync_sender.send(3).unwrap();
/// shared_sync_sender.send(4).unwrap();
///
/// let mut received = [sync_receiver.recv().unwrap(), sync_receiver.recv().unwrap()];
/// received.sort();
/// assert_eq!(received, [3, 4]);
/// ```
#[unstable(feature = "share_trait", issue = "156756")]
pub trait Share: Clone {
/// Creates another alias to the same underlying resource or shared state.
///
/// This is equivalent to calling [`Clone::clone`].
#[unstable(feature = "share_trait", issue = "156756")]
fn share(&self) -> Self {
Clone::clone(self)
}
}

/// Trait for objects whose [`Clone`] impl is lightweight (e.g. reference-counted)
///
/// Cloning an object implementing this trait should in general:
Expand Down Expand Up @@ -601,7 +685,7 @@ unsafe impl CloneToUninit for crate::bstr::ByteStr {
/// are implemented in `traits::SelectionContext::copy_clone_conditions()`
/// in `rustc_trait_selection`.
mod impls {
use super::TrivialClone;
use super::{Share, TrivialClone};
use crate::marker::PointeeSized;

macro_rules! impl_clone {
Expand Down Expand Up @@ -689,6 +773,9 @@ mod impls {
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
unsafe impl<T: PointeeSized> const TrivialClone for &T {}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T: PointeeSized> Share for &T {}

/// Shared references can be cloned, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PointeeSized> !Clone for &mut T {}
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@
#![feature(random)]
#![feature(raw_os_error_ty)]
#![feature(seek_io_take_position)]
#![feature(share_trait)]
#![feature(slice_internals)]
#![feature(slice_ptr_get)]
#![feature(slice_range)]
Expand Down
8 changes: 8 additions & 0 deletions library/std/src/sync/mpsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@
// not exposed publicly, but if you are curious about the implementation,
// that's where everything is.

use core::clone::Share;

use crate::sync::mpmc;
use crate::time::{Duration, Instant};
use crate::{error, fmt};
Expand Down Expand Up @@ -645,6 +647,9 @@ impl<T> Clone for Sender<T> {
}
}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T> Share for Sender<T> {}

#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down Expand Up @@ -774,6 +779,9 @@ impl<T> Clone for SyncSender<T> {
}
}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T> Share for SyncSender<T> {}

#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for SyncSender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
4 changes: 4 additions & 0 deletions tests/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,10 @@ In this directory, multiple crates are compiled, but some of them have `inline`

Tests on name shadowing.

## `tests/ui/share-trait`

Tests for the unstable `Share` trait.

## `tests/ui/shell-argfiles/`: `-Z shell-argfiles` command line flag

The `-Zshell-argfiles` compiler flag allows argfiles to be parsed using POSIX "shell-style" quoting. When enabled, the compiler will use shlex to parse the arguments from argfiles specified with `@shell:<path>`.
Expand Down
31 changes: 31 additions & 0 deletions tests/ui/share-trait/share-trait-arc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//@ run-pass

#![feature(share_trait)]

use std::clone::Share;
use std::sync::{Arc, Mutex};

trait Value {
fn get(&self) -> i32;
}

impl Value for Mutex<i32> {
fn get(&self) -> i32 {
*self.lock().unwrap()
}
}

fn main() {
let value = Arc::new(Mutex::new(1));
let shared = value.share();

assert!(Arc::ptr_eq(&value, &shared));
*shared.lock().unwrap() = 2;
assert_eq!(*value.lock().unwrap(), 2);

let dyn_value: Arc<dyn Value + Send + Sync> = Arc::new(Mutex::new(3));
let shared_dyn_value = dyn_value.share();

assert!(Arc::ptr_eq(&dyn_value, &shared_dyn_value));
assert_eq!(shared_dyn_value.get(), 3);
}
19 changes: 19 additions & 0 deletions tests/ui/share-trait/share-trait-mpsc-sender.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//@ run-pass

#![feature(share_trait)]

use std::clone::Share;
use std::sync::mpsc::channel;

fn main() {
let (sender, receiver) = channel();
let shared_sender = sender.share();

sender.send(1).unwrap();
shared_sender.send(2).unwrap();

let mut received = [receiver.recv().unwrap(), receiver.recv().unwrap()];
received.sort();

assert_eq!(received, [1, 2]);
}
19 changes: 19 additions & 0 deletions tests/ui/share-trait/share-trait-mpsc-sync-sender.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//@ run-pass

#![feature(share_trait)]

use std::clone::Share;
use std::sync::mpsc::sync_channel;

fn main() {
let (sender, receiver) = sync_channel(2);
let shared_sender = sender.share();

sender.send(1).unwrap();
shared_sender.send(2).unwrap();

let mut received = [receiver.recv().unwrap(), receiver.recv().unwrap()];
received.sort();

assert_eq!(received, [1, 2]);
}
20 changes: 20 additions & 0 deletions tests/ui/share-trait/share-trait-no-feature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::clone::Share;
//~^ ERROR use of unstable library feature `share_trait`

#[derive(Clone)]
struct Alias;

impl Share for Alias {}
//~^ ERROR use of unstable library feature `share_trait`

fn share_generic<T: Share>(value: &T) -> T {
//~^ ERROR use of unstable library feature `share_trait`
value.share()
//~^ ERROR use of unstable library feature `share_trait`
}

fn main() {
let value = Alias;
let _ = Share::share(&value);
//~^ ERROR use of unstable library feature `share_trait`
}
53 changes: 53 additions & 0 deletions tests/ui/share-trait/share-trait-no-feature.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
error[E0658]: use of unstable library feature `share_trait`
--> $DIR/share-trait-no-feature.rs:1:5
|
LL | use std::clone::Share;
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #156756 <https://github.com/rust-lang/rust/issues/156756> for more information
= help: add `#![feature(share_trait)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: use of unstable library feature `share_trait`
--> $DIR/share-trait-no-feature.rs:7:6
|
LL | impl Share for Alias {}
| ^^^^^
|
= note: see issue #156756 <https://github.com/rust-lang/rust/issues/156756> for more information
= help: add `#![feature(share_trait)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: use of unstable library feature `share_trait`
--> $DIR/share-trait-no-feature.rs:10:21
|
LL | fn share_generic<T: Share>(value: &T) -> T {
| ^^^^^
|
= note: see issue #156756 <https://github.com/rust-lang/rust/issues/156756> for more information
= help: add `#![feature(share_trait)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: use of unstable library feature `share_trait`
--> $DIR/share-trait-no-feature.rs:18:13
|
LL | let _ = Share::share(&value);
| ^^^^^^^^^^^^
|
= note: see issue #156756 <https://github.com/rust-lang/rust/issues/156756> for more information
= help: add `#![feature(share_trait)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: use of unstable library feature `share_trait`
--> $DIR/share-trait-no-feature.rs:12:11
|
LL | value.share()
| ^^^^^
|
= note: see issue #156756 <https://github.com/rust-lang/rust/issues/156756> for more information
= help: add `#![feature(share_trait)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0658`.
19 changes: 19 additions & 0 deletions tests/ui/share-trait/share-trait-non-implementors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#![feature(share_trait)]

use std::clone::Share;

fn require_share<T: Share>() {}

fn main() {
require_share::<&mut i32>();
//~^ ERROR the trait bound `&mut i32: Share` is not satisfied

require_share::<String>();
//~^ ERROR the trait bound `String: Share` is not satisfied

require_share::<Vec<i32>>();
//~^ ERROR the trait bound `Vec<i32>: Share` is not satisfied

require_share::<Box<i32>>();
//~^ ERROR the trait bound `Box<i32>: Share` is not satisfied
}
Loading
Loading