less garbage, more examples

This commit is contained in:
Ralf Jung 2024-06-06 08:04:34 +02:00
parent 64e7337be5
commit 05b7f282e8
3 changed files with 79 additions and 11 deletions

View File

@ -1276,7 +1276,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// valid for zero sized reads if the vector didn't allocate. /// valid for zero sized reads if the vector didn't allocate.
/// ///
/// The caller must ensure that the vector outlives the pointer this /// The caller must ensure that the vector outlives the pointer this
/// function returns, or else it will end up pointing to garbage. /// function returns, or else it will end up dangling.
/// Modifying the vector may cause its buffer to be reallocated, /// Modifying the vector may cause its buffer to be reallocated,
/// which would also make any pointers to it invalid. /// which would also make any pointers to it invalid.
/// ///
@ -1336,7 +1336,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// raw pointer valid for zero sized reads if the vector didn't allocate. /// raw pointer valid for zero sized reads if the vector didn't allocate.
/// ///
/// The caller must ensure that the vector outlives the pointer this /// The caller must ensure that the vector outlives the pointer this
/// function returns, or else it will end up pointing to garbage. /// function returns, or else it will end up dangling.
/// Modifying the vector may cause its buffer to be reallocated, /// Modifying the vector may cause its buffer to be reallocated,
/// which would also make any pointers to it invalid. /// which would also make any pointers to it invalid.
/// ///

View File

@ -777,17 +777,51 @@ where
/// Convert a reference to a raw pointer. /// Convert a reference to a raw pointer.
/// ///
/// For `r: &T`, `from_ref(r)` is equivalent to `r as *const T`, but is a bit safer since it will /// For `r: &T`, `from_ref(r)` is equivalent to `r as *const T` (except for the caveat noted below),
/// never silently change type or mutability, in particular if the code is refactored. /// but is a bit safer since it will never silently change type or mutability, in particular if the
/// code is refactored.
/// ///
/// The caller must ensure that the pointee outlives the pointer this function returns, or else it /// The caller must ensure that the pointee outlives the pointer this function returns, or else it
/// will end up pointing to garbage. /// will end up dangling.
/// ///
/// The caller must also ensure that the memory the pointer (non-transitively) points to is never /// The caller must also ensure that the memory the pointer (non-transitively) points to is never
/// written to (except inside an `UnsafeCell`) using this pointer or any pointer derived from it. If /// written to (except inside an `UnsafeCell`) using this pointer or any pointer derived from it. If
/// you need to mutate the pointee, use [`from_mut`]`. Specifically, to turn a mutable reference `m: /// you need to mutate the pointee, use [`from_mut`]`. Specifically, to turn a mutable reference `m:
/// &mut T` into `*const T`, prefer `from_mut(m).cast_const()` to obtain a pointer that can later be /// &mut T` into `*const T`, prefer `from_mut(m).cast_const()` to obtain a pointer that can later be
/// used for mutation. /// used for mutation.
///
/// ## Interaction with lifetime extension
///
/// Note that this has subtle interactions with the rules for lifetime extension of temporaries in
/// tail expressions. This code is valid, albeit in a non-obvious way:
/// ```rust
/// # type T = i32;
/// # fn foo() -> T { 42 }
/// // The temporary holding the return value of `foo` has its lifetime extended,
/// // because the surrounding expression involves no function call.
/// let p = &foo() as *const T;
/// unsafe { p.read() };
/// ```
/// Naively replacing the cast with `from_ref` is not valid:
/// ```rust,no_run
/// # use std::ptr;
/// # type T = i32;
/// # fn foo() -> T { 42 }
/// // The temporary holding the return value of `foo` does *not* have its lifetime extended,
/// // because the surrounding expression involves no function call.
/// let p = ptr::from_ref(&foo());
/// unsafe { p.read() }; // UB! Reading from a dangling pointer ⚠️
/// ```
/// The recommended way to write this code is to avoid relying on lifetime extension
/// when raw pointers are involved:
/// ```rust
/// # use std::ptr;
/// # type T = i32;
/// # fn foo() -> T { 42 }
/// let x = foo();
/// let p = ptr::from_ref(&x);
/// unsafe { p.read() };
/// ```
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
#[stable(feature = "ptr_from_ref", since = "1.76.0")] #[stable(feature = "ptr_from_ref", since = "1.76.0")]
@ -800,11 +834,45 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
/// Convert a mutable reference to a raw pointer. /// Convert a mutable reference to a raw pointer.
/// ///
/// The caller must ensure that the pointee outlives the pointer this function returns, or else it /// For `r: &mut T`, `from_mut(r)` is equivalent to `r as *mut T` (except for the caveat noted
/// will end up pointing to garbage. /// below), but is a bit safer since it will never silently change type or mutability, in particular
/// if the code is refactored.
/// ///
/// For `r: &mut T`, `from_mut(r)` is equivalent to `r as *mut T`, but is a bit safer since it will /// The caller must ensure that the pointee outlives the pointer this function returns, or else it
/// never silently change type or mutability, in particular if the code is refactored. /// will end up dangling.
///
/// ## Interaction with lifetime extension
///
/// Note that this has subtle interactions with the rules for lifetime extension of temporaries in
/// tail expressions. This code is valid, albeit in a non-obvious way:
/// ```rust
/// # type T = i32;
/// # fn foo() -> T { 42 }
/// // The temporary holding the return value of `foo` has its lifetime extended,
/// // because the surrounding expression involves no function call.
/// let p = &mut foo() as *mut T;
/// unsafe { p.write(T::default()) };
/// ```
/// Naively replacing the cast with `from_mut` is not valid:
/// ```rust,no_run
/// # use std::ptr;
/// # type T = i32;
/// # fn foo() -> T { 42 }
/// // The temporary holding the return value of `foo` does *not* have its lifetime extended,
/// // because the surrounding expression involves no function call.
/// let p = ptr::from_mut(&mut foo());
/// unsafe { p.write(T::default()) }; // UB! Writing to a dangling pointer ⚠️
/// ```
/// The recommended way to write this code is to avoid relying on lifetime extension
/// when raw pointers are involved:
/// ```rust
/// # use std::ptr;
/// # type T = i32;
/// # fn foo() -> T { 42 }
/// let mut x = foo();
/// let p = ptr::from_mut(&mut x);
/// unsafe { p.write(T::default()) };
/// ```
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
#[stable(feature = "ptr_from_ref", since = "1.76.0")] #[stable(feature = "ptr_from_ref", since = "1.76.0")]

View File

@ -731,7 +731,7 @@ impl<T> [T] {
/// Returns a raw pointer to the slice's buffer. /// Returns a raw pointer to the slice's buffer.
/// ///
/// The caller must ensure that the slice outlives the pointer this /// The caller must ensure that the slice outlives the pointer this
/// function returns, or else it will end up pointing to garbage. /// function returns, or else it will end up dangling.
/// ///
/// The caller must also ensure that the memory the pointer (non-transitively) points to /// The caller must also ensure that the memory the pointer (non-transitively) points to
/// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
@ -766,7 +766,7 @@ impl<T> [T] {
/// Returns an unsafe mutable pointer to the slice's buffer. /// Returns an unsafe mutable pointer to the slice's buffer.
/// ///
/// The caller must ensure that the slice outlives the pointer this /// The caller must ensure that the slice outlives the pointer this
/// function returns, or else it will end up pointing to garbage. /// function returns, or else it will end up dangling.
/// ///
/// Modifying the container referenced by this slice may cause its buffer /// Modifying the container referenced by this slice may cause its buffer
/// to be reallocated, which would also make any pointers to it invalid. /// to be reallocated, which would also make any pointers to it invalid.