Skip to content

Commit 0a3ca1e

Browse files
committed
Use a pointer in cell::RefMut so it's not noalias
1 parent f5f2874 commit 0a3ca1e

File tree

1 file changed

+30
-22
lines changed

1 file changed

+30
-22
lines changed

core/src/cell.rs

+30-22
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@
194194

195195
use crate::cmp::Ordering;
196196
use crate::fmt::{self, Debug, Display};
197-
use crate::marker::Unsize;
197+
use crate::marker::{PhantomData, Unsize};
198198
use crate::mem;
199199
use crate::ops::{CoerceUnsized, Deref, DerefMut};
200200
use crate::ptr::{self, NonNull};
@@ -981,8 +981,9 @@ impl<T: ?Sized> RefCell<T> {
981981
self.borrowed_at.set(Some(crate::panic::Location::caller()));
982982
}
983983

984-
// SAFETY: `BorrowRef` guarantees unique access.
985-
Ok(RefMut { value: unsafe { &mut *self.value.get() }, borrow: b })
984+
// SAFETY: `BorrowRefMut` guarantees unique access.
985+
let value = unsafe { NonNull::new_unchecked(self.value.get()) };
986+
Ok(RefMut { value, borrow: b, marker: PhantomData })
986987
}
987988
None => Err(BorrowMutError {
988989
// If a borrow occurred, then we must already have an outstanding borrow,
@@ -1515,13 +1516,13 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
15151516
/// ```
15161517
#[stable(feature = "cell_map", since = "1.8.0")]
15171518
#[inline]
1518-
pub fn map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U>
1519+
pub fn map<U: ?Sized, F>(mut orig: RefMut<'b, T>, f: F) -> RefMut<'b, U>
15191520
where
15201521
F: FnOnce(&mut T) -> &mut U,
15211522
{
15221523
// FIXME(nll-rfc#40): fix borrow-check
1523-
let RefMut { value, borrow } = orig;
1524-
RefMut { value: f(value), borrow }
1524+
let value = NonNull::from(f(&mut *orig));
1525+
RefMut { value, borrow: orig.borrow, marker: PhantomData }
15251526
}
15261527

15271528
/// Makes a new `RefMut` for an optional component of the borrowed data. The
@@ -1556,23 +1557,20 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
15561557
/// ```
15571558
#[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")]
15581559
#[inline]
1559-
pub fn filter_map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> Result<RefMut<'b, U>, Self>
1560+
pub fn filter_map<U: ?Sized, F>(mut orig: RefMut<'b, T>, f: F) -> Result<RefMut<'b, U>, Self>
15601561
where
15611562
F: FnOnce(&mut T) -> Option<&mut U>,
15621563
{
15631564
// FIXME(nll-rfc#40): fix borrow-check
1564-
let RefMut { value, borrow } = orig;
1565-
let value = value as *mut T;
15661565
// SAFETY: function holds onto an exclusive reference for the duration
15671566
// of its call through `orig`, and the pointer is only de-referenced
15681567
// inside of the function call never allowing the exclusive reference to
15691568
// escape.
1570-
match f(unsafe { &mut *value }) {
1571-
Some(value) => Ok(RefMut { value, borrow }),
1572-
None => {
1573-
// SAFETY: same as above.
1574-
Err(RefMut { value: unsafe { &mut *value }, borrow })
1569+
match f(&mut *orig) {
1570+
Some(value) => {
1571+
Ok(RefMut { value: NonNull::from(value), borrow: orig.borrow, marker: PhantomData })
15751572
}
1573+
None => Err(orig),
15761574
}
15771575
}
15781576

@@ -1604,15 +1602,18 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
16041602
#[stable(feature = "refcell_map_split", since = "1.35.0")]
16051603
#[inline]
16061604
pub fn map_split<U: ?Sized, V: ?Sized, F>(
1607-
orig: RefMut<'b, T>,
1605+
mut orig: RefMut<'b, T>,
16081606
f: F,
16091607
) -> (RefMut<'b, U>, RefMut<'b, V>)
16101608
where
16111609
F: FnOnce(&mut T) -> (&mut U, &mut V),
16121610
{
1613-
let (a, b) = f(orig.value);
16141611
let borrow = orig.borrow.clone();
1615-
(RefMut { value: a, borrow }, RefMut { value: b, borrow: orig.borrow })
1612+
let (a, b) = f(&mut *orig);
1613+
(
1614+
RefMut { value: NonNull::from(a), borrow, marker: PhantomData },
1615+
RefMut { value: NonNull::from(b), borrow: orig.borrow, marker: PhantomData },
1616+
)
16161617
}
16171618

16181619
/// Convert into a mutable reference to the underlying data.
@@ -1638,14 +1639,15 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
16381639
/// assert!(cell.try_borrow_mut().is_err());
16391640
/// ```
16401641
#[unstable(feature = "cell_leak", issue = "69099")]
1641-
pub fn leak(orig: RefMut<'b, T>) -> &'b mut T {
1642+
pub fn leak(mut orig: RefMut<'b, T>) -> &'b mut T {
16421643
// By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell can't
16431644
// go back to UNUSED within the lifetime `'b`. Resetting the reference tracking state would
16441645
// require a unique reference to the borrowed RefCell. No further references can be created
16451646
// from the original cell within that lifetime, making the current borrow the only
16461647
// reference for the remaining lifetime.
16471648
mem::forget(orig.borrow);
1648-
orig.value
1649+
// SAFETY: after forgetting, we can form a reference for the rest of lifetime `'b`.
1650+
unsafe { orig.value.as_mut() }
16491651
}
16501652
}
16511653

@@ -1700,8 +1702,12 @@ impl<'b> BorrowRefMut<'b> {
17001702
#[stable(feature = "rust1", since = "1.0.0")]
17011703
#[must_not_suspend = "holding a RefMut across suspend points can cause BorrowErrors"]
17021704
pub struct RefMut<'b, T: ?Sized + 'b> {
1703-
value: &'b mut T,
1705+
// NB: we use a pointer instead of `&'b mut T` to avoid `noalias` violations, because a
1706+
// `RefMut` argument doesn't hold exclusivity for its whole scope, only until it drops.
1707+
value: NonNull<T>,
17041708
borrow: BorrowRefMut<'b>,
1709+
// NonNull is covariant over T, so we need to reintroduce invariance.
1710+
marker: PhantomData<&'b mut T>,
17051711
}
17061712

17071713
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1710,15 +1716,17 @@ impl<T: ?Sized> Deref for RefMut<'_, T> {
17101716

17111717
#[inline]
17121718
fn deref(&self) -> &T {
1713-
self.value
1719+
// SAFETY: the value is accessible as long as we hold our borrow.
1720+
unsafe { self.value.as_ref() }
17141721
}
17151722
}
17161723

17171724
#[stable(feature = "rust1", since = "1.0.0")]
17181725
impl<T: ?Sized> DerefMut for RefMut<'_, T> {
17191726
#[inline]
17201727
fn deref_mut(&mut self) -> &mut T {
1721-
self.value
1728+
// SAFETY: the value is accessible as long as we hold our borrow.
1729+
unsafe { self.value.as_mut() }
17221730
}
17231731
}
17241732

0 commit comments

Comments
 (0)