Auto merge of #113859 - Manishearth:vec-as-mut-ptr-stacked-borrow, r=dtolnay

Add note that Vec::as_mut_ptr() does not materialize a reference to the internal buffer

See discussion on https://github.com/thomcc/rust-typed-arena/issues/62 and [t-opsem](https://rust-lang.zulipchat.com/#narrow/stream/136281-t-opsem/topic/is.20this.20typed_arena.20code.20sound.20under.20stacked.2Ftree.20borrows.3F)

This method already does the correct thing here, but it is worth guaranteeing that it does so it can be used more freely in unsafe code without having to worry about potential Stacked/Tree Borrows violations. This moves one more unsafe usage pattern from the "very likely sound but technically not fully defined" box into "definitely sound", and currently our surface area of the latter is woefully small.

I'm not sure how best to word this, opening this PR as a way to start discussion.
This commit is contained in:
bors 2023-08-29 06:04:55 +00:00
commit cedbe5c715

View File

@ -1218,6 +1218,15 @@ impl<T, A: Allocator> Vec<T, A> {
/// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
/// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
///
/// This method guarantees that for the purpose of the aliasing model, this method
/// does not materialize a reference to the underlying slice, and thus the returned pointer
/// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
/// Note that calling other methods that materialize mutable references to the slice,
/// or mutable references to specific elements you are planning on accessing through this pointer,
/// as well as writing to those elements, may still invalidate this pointer.
/// See the second example below for how this guarantee can be used.
///
///
/// # Examples
///
/// ```
@ -1231,7 +1240,23 @@ impl<T, A: Allocator> Vec<T, A> {
/// }
/// ```
///
/// Due to the aliasing guarantee, the following code is legal:
///
/// ```rust
/// unsafe {
/// let mut v = vec![0, 1, 2];
/// let ptr1 = v.as_ptr();
/// let _ = ptr1.read();
/// let ptr2 = v.as_mut_ptr().offset(2);
/// ptr2.write(2);
/// // Notably, the write to `ptr2` did *not* invalidate `ptr1`
/// // because it mutated a different element:
/// let _ = ptr1.read();
/// }
/// ```
///
/// [`as_mut_ptr`]: Vec::as_mut_ptr
/// [`as_ptr`]: Vec::as_ptr
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
#[inline]
pub fn as_ptr(&self) -> *const T {
@ -1248,6 +1273,15 @@ impl<T, A: Allocator> Vec<T, A> {
/// Modifying the vector may cause its buffer to be reallocated,
/// which would also make any pointers to it invalid.
///
/// This method guarantees that for the purpose of the aliasing model, this method
/// does not materialize a reference to the underlying slice, and thus the returned pointer
/// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
/// Note that calling other methods that materialize references to the slice,
/// or references to specific elements you are planning on accessing through this pointer,
/// may still invalidate this pointer.
/// See the second example below for how this guarantee can be used.
///
///
/// # Examples
///
/// ```
@ -1265,6 +1299,23 @@ impl<T, A: Allocator> Vec<T, A> {
/// }
/// assert_eq!(&*x, &[0, 1, 2, 3]);
/// ```
///
/// Due to the aliasing guarantee, the following code is legal:
///
/// ```rust
/// unsafe {
/// let mut v = vec![0];
/// let ptr1 = v.as_mut_ptr();
/// ptr1.write(1);
/// let ptr2 = v.as_mut_ptr();
/// ptr2.write(2);
/// // Notably, the write to `ptr2` did *not* invalidate `ptr1`:
/// ptr1.write(3);
/// }
/// ```
///
/// [`as_mut_ptr`]: Vec::as_mut_ptr
/// [`as_ptr`]: Vec::as_ptr
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {