From 57d8289754767e046a01abaab6054b7146c51f74 Mon Sep 17 00:00:00 2001 From: P1start Date: Thu, 23 Apr 2015 22:53:54 +1200 Subject: [PATCH] Make `UnsafeCell`, `RefCell`, `Mutex`, and `RwLock` accept DSTs This + DST coercions (#24619) would allow code like `Rc>>` to be simplified to `Rc>`. --- src/libcore/cell.rs | 67 ++++++++++++++++-------------- src/libcore/fmt/mod.rs | 6 +-- src/libcoretest/cell.rs | 24 +++++++++++ src/libstd/sync/mutex.rs | 44 +++++++++++++------- src/libstd/sync/rwlock.rs | 53 ++++++++++++++--------- src/test/compile-fail/bad-sized.rs | 4 -- 6 files changed, 126 insertions(+), 72 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 9ff447a87f1..c717b608a24 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -144,7 +144,7 @@ use clone::Clone; use cmp::PartialEq; use default::Default; -use marker::{Copy, Send, Sync}; +use marker::{Copy, Send, Sync, Sized}; use ops::{Deref, DerefMut, Drop}; use option::Option; use option::Option::{None, Some}; @@ -266,9 +266,9 @@ impl PartialEq for Cell { /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] -pub struct RefCell { - value: UnsafeCell, +pub struct RefCell { borrow: Cell, + value: UnsafeCell, } /// An enumeration of values returned from the `state` method on a `RefCell`. @@ -328,7 +328,9 @@ impl RefCell { debug_assert!(self.borrow.get() == UNUSED); unsafe { self.value.into_inner() } } +} +impl RefCell { /// Query the current state of this `RefCell` /// /// The returned value can be dispatched on to determine if a call to @@ -449,7 +451,7 @@ impl RefCell { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for RefCell where T: Send {} +unsafe impl Send for RefCell where T: Send {} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for RefCell { @@ -469,7 +471,7 @@ impl Default for RefCell { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for RefCell { +impl PartialEq for RefCell { #[inline] fn eq(&self, other: &RefCell) -> bool { *self.borrow() == *other.borrow() @@ -519,7 +521,7 @@ impl<'b> Clone for BorrowRef<'b> { /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] -pub struct Ref<'b, T:'b> { +pub struct Ref<'b, T: ?Sized + 'b> { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref _value: &'b T, @@ -527,7 +529,7 @@ pub struct Ref<'b, T:'b> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T> Deref for Ref<'b, T> { +impl<'b, T: ?Sized> Deref for Ref<'b, T> { type Target = T; #[inline] @@ -582,7 +584,7 @@ impl<'b> BorrowRefMut<'b> { /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] -pub struct RefMut<'b, T:'b> { +pub struct RefMut<'b, T: ?Sized + 'b> { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref _value: &'b mut T, @@ -590,7 +592,7 @@ pub struct RefMut<'b, T:'b> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T> Deref for RefMut<'b, T> { +impl<'b, T: ?Sized> Deref for RefMut<'b, T> { type Target = T; #[inline] @@ -600,7 +602,7 @@ impl<'b, T> Deref for RefMut<'b, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T> DerefMut for RefMut<'b, T> { +impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> { #[inline] fn deref_mut<'a>(&'a mut self) -> &'a mut T { self._value @@ -633,7 +635,7 @@ impl<'b, T> DerefMut for RefMut<'b, T> { /// recommended to access its fields directly, `get` should be used instead. #[lang="unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct UnsafeCell { +pub struct UnsafeCell { /// Wrapped value /// /// This field should not be accessed directly, it is made public for static @@ -642,7 +644,7 @@ pub struct UnsafeCell { pub value: T, } -impl !Sync for UnsafeCell {} +impl !Sync for UnsafeCell {} impl UnsafeCell { /// Constructs a new instance of `UnsafeCell` which will wrap the specified @@ -664,25 +666,6 @@ impl UnsafeCell { UnsafeCell { value: value } } - /// Gets a mutable pointer to the wrapped value. - /// - /// # Examples - /// - /// ``` - /// use std::cell::UnsafeCell; - /// - /// let uc = UnsafeCell::new(5); - /// - /// let five = uc.get(); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self) -> *mut T { - // FIXME(#23542) Replace with type ascription. - #![allow(trivial_casts)] - &self.value as *const T as *mut T - } - /// Unwraps the value. /// /// # Unsafety @@ -703,3 +686,25 @@ impl UnsafeCell { #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn into_inner(self) -> T { self.value } } + +impl UnsafeCell { + /// Gets a mutable pointer to the wrapped value. + /// + /// # Examples + /// + /// ``` + /// use std::cell::UnsafeCell; + /// + /// let uc = UnsafeCell::new(5); + /// + /// let five = uc.get(); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get(&self) -> *mut T { + // FIXME(#23542) Replace with type ascription. + #![allow(trivial_casts)] + &self.value as *const T as *mut T + } + +} diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 73778bfd038..f8a1ef96bcc 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1062,7 +1062,7 @@ impl Debug for Cell { } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for RefCell { +impl Debug for RefCell { fn fmt(&self, f: &mut Formatter) -> Result { match self.borrow_state() { BorrowState::Unused | BorrowState::Reading => { @@ -1074,14 +1074,14 @@ impl Debug for RefCell { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T: Debug> Debug for Ref<'b, T> { +impl<'b, T: ?Sized + Debug> Debug for Ref<'b, T> { fn fmt(&self, f: &mut Formatter) -> Result { Debug::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T: Debug> Debug for RefMut<'b, T> { +impl<'b, T: ?Sized + Debug> Debug for RefMut<'b, T> { fn fmt(&self, f: &mut Formatter) -> Result { Debug::fmt(&*(self.deref()), f) } diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index 85dd1039003..0bd0b66318f 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -159,3 +159,27 @@ fn refcell_default() { let cell: RefCell = Default::default(); assert_eq!(0, *cell.borrow()); } + +#[test] +fn unsafe_cell_unsized() { + let cell: &UnsafeCell<[i32]> = &UnsafeCell::new([1, 2, 3]); + { + let val: &mut [i32] = unsafe { &mut *cell.get() }; + val[0] = 4; + val[2] = 5; + } + let comp: &mut [i32] = &mut [4, 2, 5]; + assert_eq!(unsafe { &mut *cell.get() }, comp); +} + +#[test] +fn refcell_unsized() { + let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); + { + let b = &mut *cell.borrow_mut(); + b[0] = 4; + b[2] = 5; + } + let comp: &mut [i32] = &mut [4, 2, 5]; + assert_eq!(&*cell.borrow(), comp); +} diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 30c7407a96d..222aff9188a 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -112,7 +112,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// *guard += 1; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct Mutex { +pub struct Mutex { // Note that this static mutex is in a *box*, not inlined into the struct // itself. Once a native mutex has been used once, its address can never // change (it can't be moved). This mutex type can be safely moved at any @@ -124,9 +124,9 @@ pub struct Mutex { // these are the only places where `T: Send` matters; all other // functionality works fine on a single thread. -unsafe impl Send for Mutex { } +unsafe impl Send for Mutex { } -unsafe impl Sync for Mutex { } +unsafe impl Sync for Mutex { } /// The static mutex type is provided to allow for static allocation of mutexes. /// @@ -164,7 +164,7 @@ pub struct StaticMutex { /// `Deref` and `DerefMut` implementations #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -pub struct MutexGuard<'a, T: 'a> { +pub struct MutexGuard<'a, T: ?Sized + 'a> { // funny underscores due to how Deref/DerefMut currently work (they // disregard field privacy). __lock: &'a StaticMutex, @@ -172,7 +172,7 @@ pub struct MutexGuard<'a, T: 'a> { __poison: poison::Guard, } -impl<'a, T> !marker::Send for MutexGuard<'a, T> {} +impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {} /// Static initialization of a mutex. This constant can be used to initialize /// other mutex constants. @@ -192,7 +192,9 @@ impl Mutex { data: UnsafeCell::new(t), } } +} +impl Mutex { /// Acquires a mutex, blocking the current task until it is able to do so. /// /// This function will block the local task until it is available to acquire @@ -245,7 +247,7 @@ impl Mutex { } #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Mutex { +impl Drop for Mutex { fn drop(&mut self) { // This is actually safe b/c we know that there is no further usage of // this mutex (it's up to the user to arrange for a mutex to get @@ -255,12 +257,12 @@ impl Drop for Mutex { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Mutex { +impl fmt::Debug for Mutex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_lock() { - Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", *guard), + Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard), Err(TryLockError::Poisoned(err)) => { - write!(f, "Mutex {{ data: Poisoned({:?}) }}", **err.get_ref()) + write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) }, Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ }}") } @@ -310,7 +312,7 @@ impl StaticMutex { } } -impl<'mutex, T> MutexGuard<'mutex, T> { +impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell) -> LockResult> { @@ -325,7 +327,7 @@ impl<'mutex, T> MutexGuard<'mutex, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'mutex, T> Deref for MutexGuard<'mutex, T> { +impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> { type Target = T; fn deref<'a>(&'a self) -> &'a T { @@ -333,14 +335,14 @@ impl<'mutex, T> Deref for MutexGuard<'mutex, T> { } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'mutex, T> DerefMut for MutexGuard<'mutex, T> { +impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> { fn deref_mut<'a>(&'a mut self) -> &'a mut T { unsafe { &mut *self.__data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Drop for MutexGuard<'a, T> { +impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { #[inline] fn drop(&mut self) { unsafe { @@ -350,11 +352,11 @@ impl<'a, T> Drop for MutexGuard<'a, T> { } } -pub fn guard_lock<'a, T>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { +pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { &guard.__lock.lock } -pub fn guard_poison<'a, T>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { +pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { &guard.__lock.poison } @@ -528,4 +530,16 @@ mod tests { let lock = arc.lock().unwrap(); assert_eq!(*lock, 2); } + + #[test] + fn test_mutex_unsized() { + let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); + { + let b = &mut *mutex.lock().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*mutex.lock().unwrap(), comp); + } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index a133bb01b61..9294fb64783 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -60,13 +60,13 @@ use sys_common::rwlock as sys; /// } // write lock is dropped here /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct RwLock { +pub struct RwLock { inner: Box, data: UnsafeCell, } -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} /// Structure representing a statically allocated RwLock. /// @@ -111,24 +111,24 @@ pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock { /// dropped. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -pub struct RwLockReadGuard<'a, T: 'a> { +pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { __lock: &'a StaticRwLock, __data: &'a UnsafeCell, } -impl<'a, T> !marker::Send for RwLockReadGuard<'a, T> {} +impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {} /// RAII structure used to release the exclusive write access of a lock when /// dropped. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -pub struct RwLockWriteGuard<'a, T: 'a> { +pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { __lock: &'a StaticRwLock, __data: &'a UnsafeCell, __poison: poison::Guard, } -impl<'a, T> !marker::Send for RwLockWriteGuard<'a, T> {} +impl<'a, T: ?Sized> !marker::Send for RwLockWriteGuard<'a, T> {} impl RwLock { /// Creates a new instance of an `RwLock` which is unlocked. @@ -144,7 +144,9 @@ impl RwLock { pub fn new(t: T) -> RwLock { RwLock { inner: box RW_LOCK_INIT, data: UnsafeCell::new(t) } } +} +impl RwLock { /// Locks this rwlock with shared read access, blocking the current thread /// until it can be acquired. /// @@ -250,19 +252,19 @@ impl RwLock { } #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for RwLock { +impl Drop for RwLock { fn drop(&mut self) { unsafe { self.inner.lock.destroy() } } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for RwLock { +impl fmt::Debug for RwLock { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_read() { - Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", *guard), + Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard), Err(TryLockError::Poisoned(err)) => { - write!(f, "RwLock {{ data: Poisoned({:?}) }}", **err.get_ref()) + write!(f, "RwLock {{ data: Poisoned({:?}) }}", &**err.get_ref()) }, Err(TryLockError::WouldBlock) => write!(f, "RwLock {{ }}") } @@ -341,8 +343,7 @@ impl StaticRwLock { } } -impl<'rwlock, T> RwLockReadGuard<'rwlock, T> { - +impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) -> LockResult> { poison::map_result(lock.poison.borrow(), |_| { @@ -353,8 +354,8 @@ impl<'rwlock, T> RwLockReadGuard<'rwlock, T> { }) } } -impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> { +impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| { @@ -368,33 +369,35 @@ impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'rwlock, T> Deref for RwLockReadGuard<'rwlock, T> { +impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> { type Target = T; fn deref(&self) -> &T { unsafe { &*self.__data.get() } } } + #[stable(feature = "rust1", since = "1.0.0")] -impl<'rwlock, T> Deref for RwLockWriteGuard<'rwlock, T> { +impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> { type Target = T; fn deref(&self) -> &T { unsafe { &*self.__data.get() } } } + #[stable(feature = "rust1", since = "1.0.0")] -impl<'rwlock, T> DerefMut for RwLockWriteGuard<'rwlock, T> { +impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> { fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.__data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Drop for RwLockReadGuard<'a, T> { +impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> { fn drop(&mut self) { unsafe { self.__lock.lock.read_unlock(); } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Drop for RwLockWriteGuard<'a, T> { +impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> { fn drop(&mut self) { self.__lock.poison.done(&self.__poison); unsafe { self.__lock.lock.write_unlock(); } @@ -562,4 +565,16 @@ mod tests { let lock = arc.read().unwrap(); assert_eq!(*lock, 2); } + + #[test] + fn test_rwlock_unsized() { + let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); + { + let b = &mut *rw.write().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*rw.read().unwrap(), comp); + } } diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index fca74e457c2..8c13ff70515 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -8,14 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell::RefCell; - trait Trait {} pub fn main() { let x: Vec = Vec::new(); //~^ ERROR the trait `core::marker::Sized` is not implemented //~^^ ERROR the trait `core::marker::Sized` is not implemented - let x: Vec>> = Vec::new(); - //~^ ERROR the trait `core::marker::Sized` is not implemented }