Skip to content

Commit 4d7d9d4

Browse files
authored
Rollup merge of rust-lang#95438 - m-ou-se:sync-unsafe-cell, r=joshtriplett
Add SyncUnsafeCell. This adds `SyncUnsafeCell`, which is just `UnsafeCell` except it implements `Sync`. This was first proposed under the name `RacyUnsafeCell` here: rust-lang#53639 (comment) and here: rust-lang#53639 (comment) and here: rust-lang#53639 (comment) It allows you to create an UnsafeCell that is Sync without having to wrap it in a struct first (and then implement Sync for that struct). E.g. `static X: SyncUnsafeCell<i32>`. Using a regular `UnsafeCell` as `static` is not possible, because it isn't `Sync`. We have a language workaround for it called `static mut`, but it's nice to be able to use the proper type for such unsafety instead. It also makes implementing synchronization primitives based on unsafe cells slightly less verbose, because by using `SyncUnsafeCell` for `UnsafeCell`s that are shared between threads, you don't need a separate `impl<..> Sync for ..`. Using this type also clearly documents that the cell is expected to be accessed from multiple threads.
2 parents 73148ee + f225808 commit 4d7d9d4

File tree

3 files changed

+109
-4
lines changed

3 files changed

+109
-4
lines changed

library/core/src/cell.rs

+100-3
Original file line numberDiff line numberDiff line change
@@ -1990,9 +1990,106 @@ impl<T> const From<T> for UnsafeCell<T> {
19901990
#[unstable(feature = "coerce_unsized", issue = "27732")]
19911991
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
19921992

1993+
/// [`UnsafeCell`], but [`Sync`].
1994+
///
1995+
/// This is just an `UnsafeCell`, except it implements `Sync`
1996+
/// if `T` implements `Sync`.
1997+
///
1998+
/// `UnsafeCell` doesn't implement `Sync`, to prevent accidental mis-use.
1999+
/// You can use `SyncUnsafeCell` instead of `UnsafeCell` to allow it to be
2000+
/// shared between threads, if that's intentional.
2001+
/// Providing proper synchronization is still the task of the user,
2002+
/// making this type just as unsafe to use.
2003+
///
2004+
/// See [`UnsafeCell`] for details.
2005+
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
2006+
#[repr(transparent)]
2007+
pub struct SyncUnsafeCell<T: ?Sized> {
2008+
value: UnsafeCell<T>,
2009+
}
2010+
2011+
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
2012+
unsafe impl<T: ?Sized + Sync> Sync for SyncUnsafeCell<T> {}
2013+
2014+
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
2015+
impl<T> SyncUnsafeCell<T> {
2016+
/// Constructs a new instance of `SyncUnsafeCell` which will wrap the specified value.
2017+
#[inline]
2018+
pub const fn new(value: T) -> Self {
2019+
Self { value: UnsafeCell { value } }
2020+
}
2021+
2022+
/// Unwraps the value.
2023+
#[inline]
2024+
pub const fn into_inner(self) -> T {
2025+
self.value.into_inner()
2026+
}
2027+
}
2028+
2029+
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
2030+
impl<T: ?Sized> SyncUnsafeCell<T> {
2031+
/// Gets a mutable pointer to the wrapped value.
2032+
///
2033+
/// This can be cast to a pointer of any kind.
2034+
/// Ensure that the access is unique (no active references, mutable or not)
2035+
/// when casting to `&mut T`, and ensure that there are no mutations
2036+
/// or mutable aliases going on when casting to `&T`
2037+
#[inline]
2038+
pub const fn get(&self) -> *mut T {
2039+
self.value.get()
2040+
}
2041+
2042+
/// Returns a mutable reference to the underlying data.
2043+
///
2044+
/// This call borrows the `SyncUnsafeCell` mutably (at compile-time) which
2045+
/// guarantees that we possess the only reference.
2046+
#[inline]
2047+
pub const fn get_mut(&mut self) -> &mut T {
2048+
self.value.get_mut()
2049+
}
2050+
2051+
/// Gets a mutable pointer to the wrapped value.
2052+
///
2053+
/// See [`UnsafeCell::get`] for details.
2054+
#[inline]
2055+
pub const fn raw_get(this: *const Self) -> *mut T {
2056+
// We can just cast the pointer from `SyncUnsafeCell<T>` to `T` because
2057+
// of #[repr(transparent)] on both SyncUnsafeCell and UnsafeCell.
2058+
// See UnsafeCell::raw_get.
2059+
this as *const T as *mut T
2060+
}
2061+
}
2062+
2063+
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
2064+
impl<T: Default> Default for SyncUnsafeCell<T> {
2065+
/// Creates an `SyncUnsafeCell`, with the `Default` value for T.
2066+
fn default() -> SyncUnsafeCell<T> {
2067+
SyncUnsafeCell::new(Default::default())
2068+
}
2069+
}
2070+
2071+
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
2072+
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
2073+
impl<T> const From<T> for SyncUnsafeCell<T> {
2074+
/// Creates a new `SyncUnsafeCell<T>` containing the given value.
2075+
fn from(t: T) -> SyncUnsafeCell<T> {
2076+
SyncUnsafeCell::new(t)
2077+
}
2078+
}
2079+
2080+
#[unstable(feature = "coerce_unsized", issue = "27732")]
2081+
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
2082+
impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
2083+
19932084
#[allow(unused)]
1994-
fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) {
2085+
fn assert_coerce_unsized(
2086+
a: UnsafeCell<&i32>,
2087+
b: SyncUnsafeCell<&i32>,
2088+
c: Cell<&i32>,
2089+
d: RefCell<&i32>,
2090+
) {
19952091
let _: UnsafeCell<&dyn Send> = a;
1996-
let _: Cell<&dyn Send> = b;
1997-
let _: RefCell<&dyn Send> = c;
2092+
let _: SyncUnsafeCell<&dyn Send> = b;
2093+
let _: Cell<&dyn Send> = c;
2094+
let _: RefCell<&dyn Send> = d;
19982095
}

library/core/src/fmt/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
#![stable(feature = "rust1", since = "1.0.0")]
44

5-
use crate::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
5+
use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell};
66
use crate::char::EscapeDebugExtArgs;
77
use crate::marker::PhantomData;
88
use crate::mem;
@@ -2400,6 +2400,13 @@ impl<T: ?Sized> Debug for UnsafeCell<T> {
24002400
}
24012401
}
24022402

2403+
#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
2404+
impl<T: ?Sized> Debug for SyncUnsafeCell<T> {
2405+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
2406+
f.debug_struct("SyncUnsafeCell").finish_non_exhaustive()
2407+
}
2408+
}
2409+
24032410
// If you expected tests to be here, look instead at the core/tests/fmt.rs file,
24042411
// it's a lot easier than creating all of the rt::Piece structures here.
24052412
// There are also tests in the alloc crate, for those that need allocations.

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
#![feature(const_type_id)]
140140
#![feature(const_type_name)]
141141
#![feature(const_default_impls)]
142+
#![feature(const_unsafecell_get_mut)]
142143
#![feature(core_panic)]
143144
#![feature(duration_consts_float)]
144145
#![feature(maybe_uninit_uninit_array)]

0 commit comments

Comments
 (0)