diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2022-04-04 20:41:32 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-04-04 20:41:32 +0200 |
| commit | 4d7d9d422b90c81b9e1ca347a1c139622d950f11 (patch) | |
| tree | 31fa96263a6a9f26b6029936316acfe20d09091e | |
| parent | 73148eee31b14694272751c6ab52da06af8c7744 (diff) | |
| parent | f225808f4919b7c475354fb165fe941dab91abb5 (diff) | |
Rollup merge of #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: https://github.com/rust-lang/rust/issues/53639#issuecomment-415515748 and here: https://github.com/rust-lang/rust/issues/53639#issuecomment-432741659 and here: https://github.com/rust-lang/rust/issues/53639#issuecomment-888435728 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.
| -rw-r--r-- | library/core/src/cell.rs | 103 | ||||
| -rw-r--r-- | library/core/src/fmt/mod.rs | 9 | ||||
| -rw-r--r-- | library/core/src/lib.rs | 1 |
3 files changed, 109 insertions, 4 deletions
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 9dbb5eecd46..2a49017de3c 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -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; } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 6c1d20f36e2..fac959ac734 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -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; @@ -2400,6 +2400,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. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 7dfcc36ce93..e13f50b0d7a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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)] |
