Skip to content

Commit ddc8777

Browse files
make RefCell unstably const
1 parent 617aad8 commit ddc8777

File tree

1 file changed

+97
-38
lines changed

1 file changed

+97
-38
lines changed

library/core/src/cell.rs

+97-38
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ use crate::fmt::{self, Debug, Display};
255255
use crate::marker::{PhantomData, PointerLike, Unsize};
256256
use crate::mem;
257257
use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
258+
use crate::panic::const_panic;
258259
use crate::pin::PinCoerceUnsized;
259260
use crate::ptr::{self, NonNull};
260261

@@ -796,16 +797,24 @@ impl Display for BorrowMutError {
796797
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
797798
#[track_caller]
798799
#[cold]
799-
fn panic_already_borrowed(err: BorrowMutError) -> ! {
800-
panic!("already borrowed: {:?}", err)
800+
const fn panic_already_borrowed(err: BorrowMutError) -> ! {
801+
const_panic!(
802+
"already borrowed",
803+
"already borrowed: {err:?}",
804+
err: BorrowMutError = err,
805+
)
801806
}
802807

803808
// This ensures the panicking code is outlined from `borrow` for `RefCell`.
804809
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
805810
#[track_caller]
806811
#[cold]
807-
fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
808-
panic!("already mutably borrowed: {:?}", err)
812+
const fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
813+
const_panic!(
814+
"already mutably borrowed",
815+
"already mutably borrowed: {err:?}",
816+
err: BorrowError = err,
817+
)
809818
}
810819

811820
// Positive values represent the number of `Ref` active. Negative values
@@ -825,12 +834,12 @@ type BorrowFlag = isize;
825834
const UNUSED: BorrowFlag = 0;
826835

827836
#[inline(always)]
828-
fn is_writing(x: BorrowFlag) -> bool {
837+
const fn is_writing(x: BorrowFlag) -> bool {
829838
x < UNUSED
830839
}
831840

832841
#[inline(always)]
833-
fn is_reading(x: BorrowFlag) -> bool {
842+
const fn is_reading(x: BorrowFlag) -> bool {
834843
x > UNUSED
835844
}
836845

@@ -899,8 +908,12 @@ impl<T> RefCell<T> {
899908
#[stable(feature = "refcell_replace", since = "1.24.0")]
900909
#[track_caller]
901910
#[rustc_confusables("swap")]
902-
pub fn replace(&self, t: T) -> T {
903-
mem::replace(&mut *self.borrow_mut(), t)
911+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
912+
pub const fn replace(&self, t: T) -> T {
913+
let mut s = self.borrow_mut();
914+
let t = mem::replace(s.as_mut(), t);
915+
s.const_drop();
916+
t
904917
}
905918

906919
/// Replaces the wrapped value with a new one computed from `f`, returning
@@ -950,8 +963,13 @@ impl<T> RefCell<T> {
950963
/// ```
951964
#[inline]
952965
#[stable(feature = "refcell_swap", since = "1.24.0")]
953-
pub fn swap(&self, other: &Self) {
954-
mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
966+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
967+
pub const fn swap(&self, other: &Self) {
968+
let mut s = self.borrow_mut();
969+
let mut o = other.borrow_mut();
970+
mem::swap(s.as_mut(), o.as_mut());
971+
s.const_drop();
972+
o.const_drop();
955973
}
956974
}
957975

@@ -990,7 +1008,8 @@ impl<T: ?Sized> RefCell<T> {
9901008
#[stable(feature = "rust1", since = "1.0.0")]
9911009
#[inline]
9921010
#[track_caller]
993-
pub fn borrow(&self) -> Ref<'_, T> {
1011+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1012+
pub const fn borrow(&self) -> Ref<'_, T> {
9941013
match self.try_borrow() {
9951014
Ok(b) => b,
9961015
Err(err) => panic_already_mutably_borrowed(err),
@@ -1025,14 +1044,15 @@ impl<T: ?Sized> RefCell<T> {
10251044
#[stable(feature = "try_borrow", since = "1.13.0")]
10261045
#[inline]
10271046
#[cfg_attr(feature = "debug_refcell", track_caller)]
1028-
pub fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
1047+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1048+
pub const fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
10291049
match BorrowRef::new(&self.borrow) {
10301050
Some(b) => {
10311051
#[cfg(feature = "debug_refcell")]
10321052
{
10331053
// `borrowed_at` is always the *first* active borrow
10341054
if b.borrow.get() == 1 {
1035-
self.borrowed_at.set(Some(crate::panic::Location::caller()));
1055+
self.borrowed_at.replace(Some(crate::panic::Location::caller()));
10361056
}
10371057
}
10381058

@@ -1086,7 +1106,8 @@ impl<T: ?Sized> RefCell<T> {
10861106
#[stable(feature = "rust1", since = "1.0.0")]
10871107
#[inline]
10881108
#[track_caller]
1089-
pub fn borrow_mut(&self) -> RefMut<'_, T> {
1109+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1110+
pub const fn borrow_mut(&self) -> RefMut<'_, T> {
10901111
match self.try_borrow_mut() {
10911112
Ok(b) => b,
10921113
Err(err) => panic_already_borrowed(err),
@@ -1118,12 +1139,13 @@ impl<T: ?Sized> RefCell<T> {
11181139
#[stable(feature = "try_borrow", since = "1.13.0")]
11191140
#[inline]
11201141
#[cfg_attr(feature = "debug_refcell", track_caller)]
1121-
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
1142+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1143+
pub const fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
11221144
match BorrowRefMut::new(&self.borrow) {
11231145
Some(b) => {
11241146
#[cfg(feature = "debug_refcell")]
11251147
{
1126-
self.borrowed_at.set(Some(crate::panic::Location::caller()));
1148+
self.borrowed_at.replace(Some(crate::panic::Location::caller()));
11271149
}
11281150

11291151
// SAFETY: `BorrowRefMut` guarantees unique access.
@@ -1154,7 +1176,8 @@ impl<T: ?Sized> RefCell<T> {
11541176
#[stable(feature = "cell_as_ptr", since = "1.12.0")]
11551177
#[rustc_as_ptr]
11561178
#[rustc_never_returns_null_ptr]
1157-
pub fn as_ptr(&self) -> *mut T {
1179+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1180+
pub const fn as_ptr(&self) -> *mut T {
11581181
self.value.get()
11591182
}
11601183

@@ -1187,7 +1210,8 @@ impl<T: ?Sized> RefCell<T> {
11871210
/// ```
11881211
#[inline]
11891212
#[stable(feature = "cell_get_mut", since = "1.11.0")]
1190-
pub fn get_mut(&mut self) -> &mut T {
1213+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1214+
pub const fn get_mut(&mut self) -> &mut T {
11911215
self.value.get_mut()
11921216
}
11931217

@@ -1213,7 +1237,8 @@ impl<T: ?Sized> RefCell<T> {
12131237
/// assert!(c.try_borrow().is_ok());
12141238
/// ```
12151239
#[unstable(feature = "cell_leak", issue = "69099")]
1216-
pub fn undo_leak(&mut self) -> &mut T {
1240+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1241+
pub const fn undo_leak(&mut self) -> &mut T {
12171242
*self.borrow.get_mut() = UNUSED;
12181243
self.get_mut()
12191244
}
@@ -1247,7 +1272,8 @@ impl<T: ?Sized> RefCell<T> {
12471272
/// ```
12481273
#[stable(feature = "borrow_state", since = "1.37.0")]
12491274
#[inline]
1250-
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
1275+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1276+
pub const unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
12511277
if !is_writing(self.borrow.get()) {
12521278
// SAFETY: We check that nobody is actively writing now, but it is
12531279
// the caller's responsibility to ensure that nobody writes until
@@ -1411,7 +1437,8 @@ struct BorrowRef<'b> {
14111437

14121438
impl<'b> BorrowRef<'b> {
14131439
#[inline]
1414-
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> {
1440+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1441+
const fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> {
14151442
let b = borrow.get().wrapping_add(1);
14161443
if !is_reading(b) {
14171444
// Incrementing borrow can result in a non-reading value (<= 0) in these cases:
@@ -1428,10 +1455,23 @@ impl<'b> BorrowRef<'b> {
14281455
// 1. It was = 0, i.e. it wasn't borrowed, and we are taking the first read borrow
14291456
// 2. It was > 0 and < isize::MAX, i.e. there were read borrows, and isize
14301457
// is large enough to represent having one more read borrow
1431-
borrow.set(b);
1458+
borrow.replace(b);
14321459
Some(BorrowRef { borrow })
14331460
}
14341461
}
1462+
#[inline]
1463+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1464+
const fn clone(&self) -> Self {
1465+
// Since this Ref exists, we know the borrow flag
1466+
// is a reading borrow.
1467+
let borrow = self.borrow.get();
1468+
debug_assert!(is_reading(borrow));
1469+
// Prevent the borrow counter from overflowing into
1470+
// a writing borrow.
1471+
assert!(borrow != BorrowFlag::MAX);
1472+
self.borrow.replace(borrow + 1);
1473+
BorrowRef { borrow: self.borrow }
1474+
}
14351475
}
14361476

14371477
impl Drop for BorrowRef<'_> {
@@ -1446,15 +1486,7 @@ impl Drop for BorrowRef<'_> {
14461486
impl Clone for BorrowRef<'_> {
14471487
#[inline]
14481488
fn clone(&self) -> Self {
1449-
// Since this Ref exists, we know the borrow flag
1450-
// is a reading borrow.
1451-
let borrow = self.borrow.get();
1452-
debug_assert!(is_reading(borrow));
1453-
// Prevent the borrow counter from overflowing into
1454-
// a writing borrow.
1455-
assert!(borrow != BorrowFlag::MAX);
1456-
self.borrow.set(borrow + 1);
1457-
BorrowRef { borrow: self.borrow }
1489+
self.clone()
14581490
}
14591491
}
14601492

@@ -1499,7 +1531,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
14991531
#[stable(feature = "cell_extras", since = "1.15.0")]
15001532
#[must_use]
15011533
#[inline]
1502-
pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
1534+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1535+
pub const fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
15031536
Ref { value: orig.value, borrow: orig.borrow.clone() }
15041537
}
15051538

@@ -1621,7 +1654,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
16211654
/// assert!(cell.try_borrow_mut().is_err());
16221655
/// ```
16231656
#[unstable(feature = "cell_leak", issue = "69099")]
1624-
pub fn leak(orig: Ref<'b, T>) -> &'b T {
1657+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1658+
pub const fn leak(orig: Ref<'b, T>) -> &'b T {
16251659
// By forgetting this Ref we ensure that the borrow counter in the RefCell can't go back to
16261660
// UNUSED within the lifetime `'b`. Resetting the reference tracking state would require a
16271661
// unique reference to the borrowed RefCell. No further mutable references can be created
@@ -1643,6 +1677,21 @@ impl<T: ?Sized + fmt::Display> fmt::Display for Ref<'_, T> {
16431677
}
16441678

16451679
impl<'b, T: ?Sized> RefMut<'b, T> {
1680+
#[inline]
1681+
const fn as_mut(&mut self) -> &mut T {
1682+
// SAFETY: the value is accessible as long as we hold our borrow.
1683+
unsafe { self.value.as_mut() }
1684+
}
1685+
1686+
#[inline]
1687+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1688+
const fn const_drop(self) {
1689+
// SAFETY: only `borrow` is `Drop`
1690+
let borrow = unsafe { ptr::read(&self.borrow) };
1691+
mem::forget(self);
1692+
borrow.const_drop();
1693+
}
1694+
16461695
/// Makes a new `RefMut` for a component of the borrowed data, e.g., an enum
16471696
/// variant.
16481697
///
@@ -1787,7 +1836,8 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
17871836
/// assert!(cell.try_borrow_mut().is_err());
17881837
/// ```
17891838
#[unstable(feature = "cell_leak", issue = "69099")]
1790-
pub fn leak(mut orig: RefMut<'b, T>) -> &'b mut T {
1839+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1840+
pub const fn leak(mut orig: RefMut<'b, T>) -> &'b mut T {
17911841
// By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell can't
17921842
// go back to UNUSED within the lifetime `'b`. Resetting the reference tracking state would
17931843
// require a unique reference to the borrowed RefCell. No further references can be created
@@ -1814,14 +1864,24 @@ impl Drop for BorrowRefMut<'_> {
18141864

18151865
impl<'b> BorrowRefMut<'b> {
18161866
#[inline]
1817-
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> {
1867+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1868+
const fn const_drop(self) {
1869+
let borrow = self.borrow.get();
1870+
debug_assert!(is_writing(borrow));
1871+
self.borrow.replace(borrow + 1);
1872+
mem::forget(self)
1873+
}
1874+
1875+
#[inline]
1876+
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1877+
const fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> {
18181878
// NOTE: Unlike BorrowRefMut::clone, new is called to create the initial
18191879
// mutable reference, and so there must currently be no existing
18201880
// references. Thus, while clone increments the mutable refcount, here
18211881
// we explicitly only allow going from UNUSED to UNUSED - 1.
18221882
match borrow.get() {
18231883
UNUSED => {
1824-
borrow.set(UNUSED - 1);
1884+
borrow.replace(UNUSED - 1);
18251885
Some(BorrowRefMut { borrow })
18261886
}
18271887
_ => None,
@@ -1874,8 +1934,7 @@ impl<T: ?Sized> Deref for RefMut<'_, T> {
18741934
impl<T: ?Sized> DerefMut for RefMut<'_, T> {
18751935
#[inline]
18761936
fn deref_mut(&mut self) -> &mut T {
1877-
// SAFETY: the value is accessible as long as we hold our borrow.
1878-
unsafe { self.value.as_mut() }
1937+
self.as_mut()
18791938
}
18801939
}
18811940

0 commit comments

Comments
 (0)