Skip to content

Commit d369045

Browse files
committed
Use a pointer in cell::Ref so it's not noalias
1 parent a7d6408 commit d369045

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

library/core/src/cell.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ use crate::fmt::{self, Debug, Display};
197197
use crate::marker::Unsize;
198198
use crate::mem;
199199
use crate::ops::{CoerceUnsized, Deref, DerefMut};
200-
use crate::ptr;
200+
use crate::ptr::{self, NonNull};
201201

202202
/// A mutable memory location.
203203
///
@@ -896,7 +896,8 @@ impl<T: ?Sized> RefCell<T> {
896896

897897
// SAFETY: `BorrowRef` ensures that there is only immutable access
898898
// to the value while borrowed.
899-
Ok(Ref { value: unsafe { &*self.value.get() }, borrow: b })
899+
let value = unsafe { NonNull::new_unchecked(self.value.get()) };
900+
Ok(Ref { value, borrow: b })
900901
}
901902
None => Err(BorrowError {
902903
// If a borrow occurred, then we must already have an outstanding borrow,
@@ -1314,7 +1315,9 @@ impl Clone for BorrowRef<'_> {
13141315
#[stable(feature = "rust1", since = "1.0.0")]
13151316
#[must_not_suspend = "holding a Ref across suspend points can cause BorrowErrors"]
13161317
pub struct Ref<'b, T: ?Sized + 'b> {
1317-
value: &'b T,
1318+
// NB: we use a pointer instead of `&'b T` to avoid `noalias` violations, because a
1319+
// `Ref` argument doesn't hold immutability for its whole scope, only until it drops.
1320+
value: NonNull<T>,
13181321
borrow: BorrowRef<'b>,
13191322
}
13201323

@@ -1324,7 +1327,8 @@ impl<T: ?Sized> Deref for Ref<'_, T> {
13241327

13251328
#[inline]
13261329
fn deref(&self) -> &T {
1327-
self.value
1330+
// SAFETY: the value is accessible as long as we hold our borrow.
1331+
unsafe { self.value.as_ref() }
13281332
}
13291333
}
13301334

@@ -1368,7 +1372,7 @@ impl<'b, T: ?Sized> Ref<'b, T> {
13681372
where
13691373
F: FnOnce(&T) -> &U,
13701374
{
1371-
Ref { value: f(orig.value), borrow: orig.borrow }
1375+
Ref { value: NonNull::from(f(&*orig)), borrow: orig.borrow }
13721376
}
13731377

13741378
/// Makes a new `Ref` for an optional component of the borrowed data. The
@@ -1399,8 +1403,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
13991403
where
14001404
F: FnOnce(&T) -> Option<&U>,
14011405
{
1402-
match f(orig.value) {
1403-
Some(value) => Ok(Ref { value, borrow: orig.borrow }),
1406+
match f(&*orig) {
1407+
Some(value) => Ok(Ref { value: NonNull::from(value), borrow: orig.borrow }),
14041408
None => Err(orig),
14051409
}
14061410
}
@@ -1431,9 +1435,12 @@ impl<'b, T: ?Sized> Ref<'b, T> {
14311435
where
14321436
F: FnOnce(&T) -> (&U, &V),
14331437
{
1434-
let (a, b) = f(orig.value);
1438+
let (a, b) = f(&*orig);
14351439
let borrow = orig.borrow.clone();
1436-
(Ref { value: a, borrow }, Ref { value: b, borrow: orig.borrow })
1440+
(
1441+
Ref { value: NonNull::from(a), borrow },
1442+
Ref { value: NonNull::from(b), borrow: orig.borrow },
1443+
)
14371444
}
14381445

14391446
/// Convert into a reference to the underlying data.
@@ -1467,7 +1474,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
14671474
// unique reference to the borrowed RefCell. No further mutable references can be created
14681475
// from the original cell.
14691476
mem::forget(orig.borrow);
1470-
orig.value
1477+
// SAFETY: after forgetting, we can form a reference for the rest of lifetime `'b`.
1478+
unsafe { orig.value.as_ref() }
14711479
}
14721480
}
14731481

0 commit comments

Comments
 (0)