mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
make RefCell unstably const
This commit is contained in:
+63
-35
@@ -255,6 +255,7 @@
|
||||
use crate::marker::{PhantomData, PointerLike, Unsize};
|
||||
use crate::mem;
|
||||
use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
|
||||
use crate::panic::const_panic;
|
||||
use crate::pin::PinCoerceUnsized;
|
||||
use crate::ptr::{self, NonNull};
|
||||
|
||||
@@ -781,16 +782,24 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
fn panic_already_borrowed(err: BorrowMutError) -> ! {
|
||||
panic!("{err}")
|
||||
const fn panic_already_borrowed(err: BorrowMutError) -> ! {
|
||||
const_panic!(
|
||||
"RefCell already borrowed",
|
||||
"{err}",
|
||||
err: BorrowMutError = err,
|
||||
)
|
||||
}
|
||||
|
||||
// This ensures the panicking code is outlined from `borrow` for `RefCell`.
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
|
||||
panic!("{err}")
|
||||
const fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
|
||||
const_panic!(
|
||||
"RefCell already mutably borrowed",
|
||||
"{err}",
|
||||
err: BorrowError = err,
|
||||
)
|
||||
}
|
||||
|
||||
// Positive values represent the number of `Ref` active. Negative values
|
||||
@@ -810,12 +819,12 @@ fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
|
||||
const UNUSED: BorrowCounter = 0;
|
||||
|
||||
#[inline(always)]
|
||||
fn is_writing(x: BorrowCounter) -> bool {
|
||||
const fn is_writing(x: BorrowCounter) -> bool {
|
||||
x < UNUSED
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_reading(x: BorrowCounter) -> bool {
|
||||
const fn is_reading(x: BorrowCounter) -> bool {
|
||||
x > UNUSED
|
||||
}
|
||||
|
||||
@@ -884,8 +893,9 @@ pub const fn into_inner(self) -> T {
|
||||
#[stable(feature = "refcell_replace", since = "1.24.0")]
|
||||
#[track_caller]
|
||||
#[rustc_confusables("swap")]
|
||||
pub fn replace(&self, t: T) -> T {
|
||||
mem::replace(&mut *self.borrow_mut(), t)
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn replace(&self, t: T) -> T {
|
||||
mem::replace(&mut self.borrow_mut(), t)
|
||||
}
|
||||
|
||||
/// Replaces the wrapped value with a new one computed from `f`, returning
|
||||
@@ -935,7 +945,8 @@ pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "refcell_swap", since = "1.24.0")]
|
||||
pub fn swap(&self, other: &Self) {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn swap(&self, other: &Self) {
|
||||
mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
|
||||
}
|
||||
}
|
||||
@@ -975,7 +986,8 @@ impl<T: ?Sized> RefCell<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn borrow(&self) -> Ref<'_, T> {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn borrow(&self) -> Ref<'_, T> {
|
||||
match self.try_borrow() {
|
||||
Ok(b) => b,
|
||||
Err(err) => panic_already_mutably_borrowed(err),
|
||||
@@ -1010,14 +1022,15 @@ pub fn borrow(&self) -> Ref<'_, T> {
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "debug_refcell", track_caller)]
|
||||
pub fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
|
||||
match BorrowRef::new(&self.borrow) {
|
||||
Some(b) => {
|
||||
#[cfg(feature = "debug_refcell")]
|
||||
{
|
||||
// `borrowed_at` is always the *first* active borrow
|
||||
if b.borrow.get() == 1 {
|
||||
self.borrowed_at.set(Some(crate::panic::Location::caller()));
|
||||
self.borrowed_at.replace(Some(crate::panic::Location::caller()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1071,7 +1084,8 @@ pub fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn borrow_mut(&self) -> RefMut<'_, T> {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn borrow_mut(&self) -> RefMut<'_, T> {
|
||||
match self.try_borrow_mut() {
|
||||
Ok(b) => b,
|
||||
Err(err) => panic_already_borrowed(err),
|
||||
@@ -1103,12 +1117,13 @@ pub fn borrow_mut(&self) -> RefMut<'_, T> {
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "debug_refcell", track_caller)]
|
||||
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
|
||||
match BorrowRefMut::new(&self.borrow) {
|
||||
Some(b) => {
|
||||
#[cfg(feature = "debug_refcell")]
|
||||
{
|
||||
self.borrowed_at.set(Some(crate::panic::Location::caller()));
|
||||
self.borrowed_at.replace(Some(crate::panic::Location::caller()));
|
||||
}
|
||||
|
||||
// SAFETY: `BorrowRefMut` guarantees unique access.
|
||||
@@ -1139,7 +1154,8 @@ pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
|
||||
#[stable(feature = "cell_as_ptr", since = "1.12.0")]
|
||||
#[rustc_as_ptr]
|
||||
#[rustc_never_returns_null_ptr]
|
||||
pub fn as_ptr(&self) -> *mut T {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn as_ptr(&self) -> *mut T {
|
||||
self.value.get()
|
||||
}
|
||||
|
||||
@@ -1176,7 +1192,8 @@ pub fn as_ptr(&self) -> *mut T {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "cell_get_mut", since = "1.11.0")]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn get_mut(&mut self) -> &mut T {
|
||||
self.value.get_mut()
|
||||
}
|
||||
|
||||
@@ -1202,7 +1219,8 @@ pub fn get_mut(&mut self) -> &mut T {
|
||||
/// assert!(c.try_borrow().is_ok());
|
||||
/// ```
|
||||
#[unstable(feature = "cell_leak", issue = "69099")]
|
||||
pub fn undo_leak(&mut self) -> &mut T {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn undo_leak(&mut self) -> &mut T {
|
||||
*self.borrow.get_mut() = UNUSED;
|
||||
self.get_mut()
|
||||
}
|
||||
@@ -1236,7 +1254,8 @@ pub fn undo_leak(&mut self) -> &mut T {
|
||||
/// ```
|
||||
#[stable(feature = "borrow_state", since = "1.37.0")]
|
||||
#[inline]
|
||||
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
|
||||
if !is_writing(self.borrow.get()) {
|
||||
// SAFETY: We check that nobody is actively writing now, but it is
|
||||
// the caller's responsibility to ensure that nobody writes until
|
||||
@@ -1400,7 +1419,7 @@ struct BorrowRef<'b> {
|
||||
|
||||
impl<'b> BorrowRef<'b> {
|
||||
#[inline]
|
||||
fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRef<'b>> {
|
||||
const fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRef<'b>> {
|
||||
let b = borrow.get().wrapping_add(1);
|
||||
if !is_reading(b) {
|
||||
// Incrementing borrow can result in a non-reading value (<= 0) in these cases:
|
||||
@@ -1417,22 +1436,24 @@ fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRef<'b>> {
|
||||
// 1. It was = 0, i.e. it wasn't borrowed, and we are taking the first read borrow
|
||||
// 2. It was > 0 and < isize::MAX, i.e. there were read borrows, and isize
|
||||
// is large enough to represent having one more read borrow
|
||||
borrow.set(b);
|
||||
borrow.replace(b);
|
||||
Some(BorrowRef { borrow })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BorrowRef<'_> {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
impl const Drop for BorrowRef<'_> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
let borrow = self.borrow.get();
|
||||
debug_assert!(is_reading(borrow));
|
||||
self.borrow.set(borrow - 1);
|
||||
self.borrow.replace(borrow - 1);
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for BorrowRef<'_> {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
impl const Clone for BorrowRef<'_> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
// Since this Ref exists, we know the borrow flag
|
||||
@@ -1442,7 +1463,7 @@ fn clone(&self) -> Self {
|
||||
// Prevent the borrow counter from overflowing into
|
||||
// a writing borrow.
|
||||
assert!(borrow != BorrowCounter::MAX);
|
||||
self.borrow.set(borrow + 1);
|
||||
self.borrow.replace(borrow + 1);
|
||||
BorrowRef { borrow: self.borrow }
|
||||
}
|
||||
}
|
||||
@@ -1463,7 +1484,8 @@ pub struct Ref<'b, T: ?Sized + 'b> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Deref for Ref<'_, T> {
|
||||
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
|
||||
impl<T: ?Sized> const Deref for Ref<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
@@ -1488,7 +1510,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
|
||||
#[stable(feature = "cell_extras", since = "1.15.0")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
|
||||
Ref { value: orig.value, borrow: orig.borrow.clone() }
|
||||
}
|
||||
|
||||
@@ -1610,7 +1633,8 @@ pub fn map_split<U: ?Sized, V: ?Sized, F>(orig: Ref<'b, T>, f: F) -> (Ref<'b, U>
|
||||
/// assert!(cell.try_borrow_mut().is_err());
|
||||
/// ```
|
||||
#[unstable(feature = "cell_leak", issue = "69099")]
|
||||
pub fn leak(orig: Ref<'b, T>) -> &'b T {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn leak(orig: Ref<'b, T>) -> &'b T {
|
||||
// By forgetting this Ref we ensure that the borrow counter in the RefCell can't go back to
|
||||
// UNUSED within the lifetime `'b`. Resetting the reference tracking state would require a
|
||||
// unique reference to the borrowed RefCell. No further mutable references can be created
|
||||
@@ -1776,7 +1800,8 @@ pub fn map_split<U: ?Sized, V: ?Sized, F>(
|
||||
/// assert!(cell.try_borrow_mut().is_err());
|
||||
/// ```
|
||||
#[unstable(feature = "cell_leak", issue = "69099")]
|
||||
pub fn leak(mut orig: RefMut<'b, T>) -> &'b mut T {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
pub const fn leak(mut orig: RefMut<'b, T>) -> &'b mut T {
|
||||
// By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell can't
|
||||
// go back to UNUSED within the lifetime `'b`. Resetting the reference tracking state would
|
||||
// require a unique reference to the borrowed RefCell. No further references can be created
|
||||
@@ -1792,25 +1817,26 @@ struct BorrowRefMut<'b> {
|
||||
borrow: &'b Cell<BorrowCounter>,
|
||||
}
|
||||
|
||||
impl Drop for BorrowRefMut<'_> {
|
||||
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
|
||||
impl const Drop for BorrowRefMut<'_> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
let borrow = self.borrow.get();
|
||||
debug_assert!(is_writing(borrow));
|
||||
self.borrow.set(borrow + 1);
|
||||
self.borrow.replace(borrow + 1);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> BorrowRefMut<'b> {
|
||||
#[inline]
|
||||
fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRefMut<'b>> {
|
||||
const fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRefMut<'b>> {
|
||||
// NOTE: Unlike BorrowRefMut::clone, new is called to create the initial
|
||||
// mutable reference, and so there must currently be no existing
|
||||
// references. Thus, while clone increments the mutable refcount, here
|
||||
// we explicitly only allow going from UNUSED to UNUSED - 1.
|
||||
match borrow.get() {
|
||||
UNUSED => {
|
||||
borrow.set(UNUSED - 1);
|
||||
borrow.replace(UNUSED - 1);
|
||||
Some(BorrowRefMut { borrow })
|
||||
}
|
||||
_ => None,
|
||||
@@ -1849,7 +1875,8 @@ pub struct RefMut<'b, T: ?Sized + 'b> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Deref for RefMut<'_, T> {
|
||||
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
|
||||
impl<T: ?Sized> const Deref for RefMut<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
@@ -1860,7 +1887,8 @@ fn deref(&self) -> &T {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> DerefMut for RefMut<'_, T> {
|
||||
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
|
||||
impl<T: ?Sized> const DerefMut for RefMut<'_, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
// SAFETY: the value is accessible as long as we hold our borrow.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use core::cell::*;
|
||||
use core::mem::forget;
|
||||
|
||||
#[test]
|
||||
fn smoketest_unsafe_cell() {
|
||||
@@ -477,3 +478,74 @@ fn const_cells() {
|
||||
const _: i32 = CELL.into_inner();
|
||||
*/
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refcell_borrow() {
|
||||
// Check that `borrow` is usable at compile-time
|
||||
const {
|
||||
let a = RefCell::new(0);
|
||||
assert!(a.try_borrow().is_ok());
|
||||
assert!(a.try_borrow_mut().is_ok());
|
||||
let a_ref = a.borrow();
|
||||
assert!(*a_ref == 0);
|
||||
assert!(a.try_borrow().is_ok());
|
||||
assert!(a.try_borrow_mut().is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refcell_borrow_mut() {
|
||||
// Check that `borrow_mut` is usable at compile-time
|
||||
const {
|
||||
let mut a = RefCell::new(0);
|
||||
{
|
||||
assert!(a.try_borrow().is_ok());
|
||||
assert!(a.try_borrow_mut().is_ok());
|
||||
let mut a_ref = a.borrow_mut();
|
||||
assert!(*a_ref == 0);
|
||||
*a_ref = 10;
|
||||
assert!(*a_ref == 10);
|
||||
assert!(a.try_borrow().is_err());
|
||||
assert!(a.try_borrow_mut().is_err());
|
||||
}
|
||||
assert!(*a.get_mut() == 10);
|
||||
};
|
||||
}
|
||||
struct NeverDrop;
|
||||
impl Drop for NeverDrop {
|
||||
fn drop(&mut self) {
|
||||
panic!("should never be called");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refcell_replace() {
|
||||
// Check that `replace` is usable at compile-time
|
||||
const {
|
||||
let a = RefCell::new(0);
|
||||
assert!(a.replace(10) == 0);
|
||||
let a = a.into_inner();
|
||||
assert!(a == 10);
|
||||
|
||||
let b = RefCell::new(NeverDrop);
|
||||
forget(b.replace(NeverDrop));
|
||||
forget(b)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refcell_swap() {
|
||||
// Check that `swap` is usable at compile-time
|
||||
const {
|
||||
let (a, b) = (RefCell::new(31), RefCell::new(41));
|
||||
a.swap(&b);
|
||||
let (a, b) = (a.into_inner(), b.into_inner());
|
||||
assert!(a == 41);
|
||||
assert!(b == 31);
|
||||
|
||||
let c = RefCell::new(NeverDrop);
|
||||
let d = RefCell::new(NeverDrop);
|
||||
c.swap(&d);
|
||||
forget((c, d));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
#![feature(cfg_target_has_reliable_f16_f128)]
|
||||
#![feature(char_max_len)]
|
||||
#![feature(clone_to_uninit)]
|
||||
#![feature(const_deref)]
|
||||
#![feature(const_destruct)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(const_float_round_methods)]
|
||||
#![feature(const_ref_cell)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(core_float_math)]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
Reference in New Issue
Block a user