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

Add SyncUnsafeCell. #95438

Merged
merged 2 commits into from
Apr 4, 2022
Merged
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
103 changes: 100 additions & 3 deletions library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1990,9 +1990,106 @@ impl<T> const From<T> for UnsafeCell<T> {
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}

/// [`UnsafeCell`], but [`Sync`].
///
/// This is just an `UnsafeCell`, except it implements `Sync`
/// if `T` implements `Sync`.
///
/// `UnsafeCell` doesn't implement `Sync`, to prevent accidental mis-use.
/// You can use `SyncUnsafeCell` instead of `UnsafeCell` to allow it to be
/// shared between threads, if that's intentional.
/// Providing proper synchronization is still the task of the user,
/// making this type just as unsafe to use.
///
/// See [`UnsafeCell`] for details.
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
#[repr(transparent)]
pub struct SyncUnsafeCell<T: ?Sized> {
value: UnsafeCell<T>,
}

#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
unsafe impl<T: ?Sized + Sync> Sync for SyncUnsafeCell<T> {}

#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
impl<T> SyncUnsafeCell<T> {
/// Constructs a new instance of `SyncUnsafeCell` which will wrap the specified value.
#[inline]
pub const fn new(value: T) -> Self {
Self { value: UnsafeCell { value } }
}

/// Unwraps the value.
#[inline]
pub const fn into_inner(self) -> T {
self.value.into_inner()
}
}

#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
impl<T: ?Sized> SyncUnsafeCell<T> {
/// Gets a mutable pointer to the wrapped value.
///
/// This can be cast to a pointer of any kind.
/// Ensure that the access is unique (no active references, mutable or not)
/// when casting to `&mut T`, and ensure that there are no mutations
/// or mutable aliases going on when casting to `&T`
#[inline]
pub const fn get(&self) -> *mut T {
self.value.get()
}

/// Returns a mutable reference to the underlying data.
///
/// This call borrows the `SyncUnsafeCell` mutably (at compile-time) which
/// guarantees that we possess the only reference.
#[inline]
pub const fn get_mut(&mut self) -> &mut T {
self.value.get_mut()
}

/// Gets a mutable pointer to the wrapped value.
///
/// See [`UnsafeCell::get`] for details.
#[inline]
pub const fn raw_get(this: *const Self) -> *mut T {
// We can just cast the pointer from `SyncUnsafeCell<T>` to `T` because
// of #[repr(transparent)] on both SyncUnsafeCell and UnsafeCell.
// See UnsafeCell::raw_get.
this as *const T as *mut T
}
}

#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
impl<T: Default> Default for SyncUnsafeCell<T> {
/// Creates an `SyncUnsafeCell`, with the `Default` value for T.
fn default() -> SyncUnsafeCell<T> {
SyncUnsafeCell::new(Default::default())
}
}

#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for SyncUnsafeCell<T> {
/// Creates a new `SyncUnsafeCell<T>` containing the given value.
fn from(t: T) -> SyncUnsafeCell<T> {
SyncUnsafeCell::new(t)
}
}

#[unstable(feature = "coerce_unsized", issue = "27732")]
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}

#[allow(unused)]
fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) {
fn assert_coerce_unsized(
a: UnsafeCell<&i32>,
b: SyncUnsafeCell<&i32>,
c: Cell<&i32>,
d: RefCell<&i32>,
) {
let _: UnsafeCell<&dyn Send> = a;
let _: Cell<&dyn Send> = b;
let _: RefCell<&dyn Send> = c;
let _: SyncUnsafeCell<&dyn Send> = b;
let _: Cell<&dyn Send> = c;
let _: RefCell<&dyn Send> = d;
}
9 changes: 8 additions & 1 deletion library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

use crate::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell};
use crate::char::EscapeDebugExtArgs;
use crate::marker::PhantomData;
use crate::mem;
Expand Down Expand Up @@ -2396,6 +2396,13 @@ impl<T: ?Sized> Debug for UnsafeCell<T> {
}
}

#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
impl<T: ?Sized> Debug for SyncUnsafeCell<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("SyncUnsafeCell").finish_non_exhaustive()
}
}

// If you expected tests to be here, look instead at the core/tests/fmt.rs file,
// it's a lot easier than creating all of the rt::Piece structures here.
// There are also tests in the alloc crate, for those that need allocations.
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
#![feature(const_type_id)]
#![feature(const_type_name)]
#![feature(const_default_impls)]
#![feature(const_unsafecell_get_mut)]
#![feature(core_panic)]
#![feature(duration_consts_float)]
#![feature(maybe_uninit_uninit_array)]
Expand Down