From 750ab0370e4e52b6c22181e1187f463ffce0a230 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 29 Mar 2022 19:30:55 +0200 Subject: [PATCH 1/2] Add SyncUnsafeCell. --- library/core/src/cell.rs | 103 ++++++++++++++++++++++++++++++++++-- library/core/src/fmt/mod.rs | 9 +++- 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 9dbb5eecd469b..8f283a7f43a06 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1990,9 +1990,106 @@ impl const From for UnsafeCell { #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U> CoerceUnsized> for UnsafeCell {} +/// [`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 = "none")] +#[repr(transparent)] +pub struct SyncUnsafeCell { + value: UnsafeCell, +} + +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +unsafe impl Sync for SyncUnsafeCell {} + +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +impl SyncUnsafeCell { + /// 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 = "none")] +impl SyncUnsafeCell { + /// 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` 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 = "none")] +impl Default for SyncUnsafeCell { + /// Creates an `SyncUnsafeCell`, with the `Default` value for T. + fn default() -> SyncUnsafeCell { + SyncUnsafeCell::new(Default::default()) + } +} + +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[rustc_const_unstable(feature = "const_convert", issue = "88674")] +impl const From for SyncUnsafeCell { + /// Creates a new `SyncUnsafeCell` containing the given value. + fn from(t: T) -> SyncUnsafeCell { + SyncUnsafeCell::new(t) + } +} + +#[unstable(feature = "coerce_unsized", issue = "27732")] +//#[unstable(feature = "sync_unsafe_cell", issue = "none")] +impl, U> CoerceUnsized> for SyncUnsafeCell {} + #[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 84cf1753f86ba..19a2140abe8b4 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; @@ -2396,6 +2396,13 @@ impl Debug for UnsafeCell { } } +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +impl Debug for SyncUnsafeCell { + 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 5c16346cbd1d9..d18df506d2b48 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)] From f225808f4919b7c475354fb165fe941dab91abb5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 29 Mar 2022 19:54:00 +0200 Subject: [PATCH 2/2] Add tracking issue for sync_unsafe_cell. --- library/core/src/cell.rs | 14 +++++++------- library/core/src/fmt/mod.rs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 8f283a7f43a06..2a49017de3cc8 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2002,16 +2002,16 @@ impl, U> CoerceUnsized> for UnsafeCell {} /// making this type just as unsafe to use. /// /// See [`UnsafeCell`] for details. -#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] #[repr(transparent)] pub struct SyncUnsafeCell { value: UnsafeCell, } -#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] unsafe impl Sync for SyncUnsafeCell {} -#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] impl SyncUnsafeCell { /// Constructs a new instance of `SyncUnsafeCell` which will wrap the specified value. #[inline] @@ -2026,7 +2026,7 @@ impl SyncUnsafeCell { } } -#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] impl SyncUnsafeCell { /// Gets a mutable pointer to the wrapped value. /// @@ -2060,7 +2060,7 @@ impl SyncUnsafeCell { } } -#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] impl Default for SyncUnsafeCell { /// Creates an `SyncUnsafeCell`, with the `Default` value for T. fn default() -> SyncUnsafeCell { @@ -2068,7 +2068,7 @@ impl Default for SyncUnsafeCell { } } -#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From for SyncUnsafeCell { /// Creates a new `SyncUnsafeCell` containing the given value. @@ -2078,7 +2078,7 @@ impl const From for SyncUnsafeCell { } #[unstable(feature = "coerce_unsized", issue = "27732")] -//#[unstable(feature = "sync_unsafe_cell", issue = "none")] +//#[unstable(feature = "sync_unsafe_cell", issue = "95439")] impl, U> CoerceUnsized> for SyncUnsafeCell {} #[allow(unused)] diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 19a2140abe8b4..3e0aea4aca9a1 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -2396,7 +2396,7 @@ impl Debug for UnsafeCell { } } -#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[unstable(feature = "sync_unsafe_cell", issue = "95439")] impl Debug for SyncUnsafeCell { fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.debug_struct("SyncUnsafeCell").finish_non_exhaustive()