summaryrefslogtreecommitdiffstats
path: root/library/core/src/cell.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src/cell.rs')
-rw-r--r--library/core/src/cell.rs51
1 files changed, 45 insertions, 6 deletions
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index bf4c682d3..3b4d99221 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -237,6 +237,7 @@
use crate::cmp::Ordering;
use crate::fmt::{self, Debug, Display};
+use crate::intrinsics::is_nonoverlapping;
use crate::marker::{PhantomData, Unsize};
use crate::mem;
use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
@@ -415,6 +416,12 @@ impl<T> Cell<T> {
/// Swaps the values of two `Cell`s.
/// Difference with `std::mem::swap` is that this function doesn't require `&mut` reference.
///
+ /// # Panics
+ ///
+ /// This function will panic if `self` and `other` are different `Cell`s that partially overlap.
+ /// (Using just standard library methods, it is impossible to create such partially overlapping `Cell`s.
+ /// However, unsafe code is allowed to e.g. create two `&Cell<[i32; 2]>` that partially overlap.)
+ ///
/// # Examples
///
/// ```
@@ -430,14 +437,20 @@ impl<T> Cell<T> {
#[stable(feature = "move_cell", since = "1.17.0")]
pub fn swap(&self, other: &Self) {
if ptr::eq(self, other) {
+ // Swapping wouldn't change anything.
return;
}
+ if !is_nonoverlapping(self, other, 1) {
+ // See <https://github.com/rust-lang/rust/issues/80778> for why we need to stop here.
+ panic!("`Cell::swap` on overlapping non-identical `Cell`s");
+ }
// SAFETY: This can be risky if called from separate threads, but `Cell`
// is `!Sync` so this won't happen. This also won't invalidate any
// pointers since `Cell` makes sure nothing else will be pointing into
- // either of these `Cell`s.
+ // either of these `Cell`s. We also excluded shenanigans like partially overlapping `Cell`s,
+ // so `swap` will just properly copy two full values of type `T` back and forth.
unsafe {
- ptr::swap(self.value.get(), other.value.get());
+ mem::swap(&mut *self.value.get(), &mut *other.value.get());
}
}
@@ -543,6 +556,7 @@ impl<T: ?Sized> Cell<T> {
#[inline]
#[stable(feature = "cell_as_ptr", since = "1.12.0")]
#[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")]
+ #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
pub const fn as_ptr(&self) -> *mut T {
self.value.get()
}
@@ -740,6 +754,22 @@ impl Display for BorrowMutError {
}
}
+// This ensures the panicking code is outlined from `borrow_mut` for `RefCell`.
+#[inline(never)]
+#[track_caller]
+#[cold]
+fn panic_already_borrowed(err: BorrowMutError) -> ! {
+ panic!("already borrowed: {:?}", err)
+}
+
+// This ensures the panicking code is outlined from `borrow` for `RefCell`.
+#[inline(never)]
+#[track_caller]
+#[cold]
+fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
+ panic!("already mutably borrowed: {:?}", err)
+}
+
// Positive values represent the number of `Ref` active. Negative values
// represent the number of `RefMut` active. Multiple `RefMut`s can only be
// active at a time if they refer to distinct, nonoverlapping components of a
@@ -921,7 +951,10 @@ impl<T: ?Sized> RefCell<T> {
#[inline]
#[track_caller]
pub fn borrow(&self) -> Ref<'_, T> {
- self.try_borrow().expect("already mutably borrowed")
+ match self.try_borrow() {
+ Ok(b) => b,
+ Err(err) => panic_already_mutably_borrowed(err),
+ }
}
/// Immutably borrows the wrapped value, returning an error if the value is currently mutably
@@ -1014,7 +1047,10 @@ impl<T: ?Sized> RefCell<T> {
#[inline]
#[track_caller]
pub fn borrow_mut(&self) -> RefMut<'_, T> {
- self.try_borrow_mut().expect("already borrowed")
+ match self.try_borrow_mut() {
+ Ok(b) => b,
+ Err(err) => panic_already_borrowed(err),
+ }
}
/// Mutably borrows the wrapped value, returning an error if the value is currently borrowed.
@@ -1076,6 +1112,7 @@ impl<T: ?Sized> RefCell<T> {
/// ```
#[inline]
#[stable(feature = "cell_as_ptr", since = "1.12.0")]
+ #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
pub fn as_ptr(&self) -> *mut T {
self.value.get()
}
@@ -1893,8 +1930,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
/// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
/// same memory layout, the following is not allowed and undefined behavior:
///
-#[cfg_attr(bootstrap, doc = "```rust,no_run")]
-#[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")]
+/// ```rust,compile_fail
/// # use std::cell::UnsafeCell;
/// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
/// let t = ptr as *const UnsafeCell<T> as *mut T;
@@ -2071,6 +2107,7 @@ impl<T: ?Sized> UnsafeCell<T> {
#[inline(always)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")]
+ #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
pub const fn get(&self) -> *mut T {
// We can just cast the pointer from `UnsafeCell<T>` to `T` because of
// #[repr(transparent)]. This exploits std's special status, there is
@@ -2131,6 +2168,7 @@ impl<T: ?Sized> UnsafeCell<T> {
#[inline(always)]
#[stable(feature = "unsafe_cell_raw_get", since = "1.56.0")]
#[rustc_const_stable(feature = "unsafe_cell_raw_get", since = "1.56.0")]
+ #[rustc_diagnostic_item = "unsafe_cell_raw_get"]
pub const fn raw_get(this: *const Self) -> *mut T {
// We can just cast the pointer from `UnsafeCell<T>` to `T` because of
// #[repr(transparent)]. This exploits std's special status, there is
@@ -2213,6 +2251,7 @@ impl<T: ?Sized> SyncUnsafeCell<T> {
/// when casting to `&mut T`, and ensure that there are no mutations
/// or mutable aliases going on when casting to `&T`
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
pub const fn get(&self) -> *mut T {
self.value.get()
}