about summary refs log tree commit diff
diff options
context:
space:
mode:
authorxizheyin <xizheyin@smail.nju.edu.cn>2025-06-04 01:39:02 +0800
committerxizheyin <xizheyin@smail.nju.edu.cn>2025-06-04 01:39:02 +0800
commit871397342c9da1cdcee3c851a2c93b84aa512fba (patch)
tree9ea7949e9fb3a628bef3fed7d9ae0facd8645ee5
parent91fad92585b2dafc52a074e502b2a6c1f093ca35 (diff)
downloadrust-871397342c9da1cdcee3c851a2c93b84aa512fba.tar.gz
rust-871397342c9da1cdcee3c851a2c93b84aa512fba.zip
std: simplify `NonNull` variance documentation
Streamlined the explanation of covariance for `NonNull<T>`,
focusing on practical usage and reducing scary explanation.
Added a concise example for cases where invariance is required,
showing how to use `PhantomData<Cell<T>>

Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
-rw-r--r--library/core/src/ptr/non_null.rs27
1 files changed, 16 insertions, 11 deletions
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 91b8d1bf9a7..f9089ae5239 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -20,19 +20,24 @@ use crate::{fmt, hash, intrinsics, mem, ptr};
 /// as a discriminant -- `Option<NonNull<T>>` has the same size as `*mut T`.
 /// However the pointer may still dangle if it isn't dereferenced.
 ///
-/// Unlike `*mut T`, `NonNull<T>` was chosen to be covariant over `T`. This makes it
-/// possible to use `NonNull<T>` when building covariant types, but introduces the
-/// risk of unsoundness if used in a type that shouldn't actually be covariant.
-/// (The opposite choice was made for `*mut T` even though technically the unsoundness
-/// could only be caused by calling unsafe functions.)
+/// Unlike `*mut T`, `NonNull<T>` is covariant over `T`. This is usually the correct
+/// choice for most data structures and safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`,
+/// and `LinkedList`.
 ///
-/// Covariance is correct for most safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`,
-/// and `LinkedList`. This is the case because they provide a public API that follows the
-/// normal shared XOR mutable rules of Rust.
+/// In rare cases, if your type exposes a way to mutate the value of `T` through a `NonNull<T>`,
+/// and you need to prevent unsoundness from variance (for example, if `T` could be a reference
+/// with a shorter lifetime), you should add a field to make your type invariant, such as
+/// `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`.
 ///
-/// If your type cannot safely be covariant, you must ensure it contains some
-/// additional field to provide invariance. Often this field will be a [`PhantomData`]
-/// type like `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`.
+/// Example of a type that must be invariant:
+/// ```rust
+/// use std::cell::Cell;
+/// use std::marker::PhantomData;
+/// struct Invariant<T> {
+///     ptr: std::ptr::NonNull<T>,
+///     _invariant: PhantomData<Cell<T>>,
+/// }
+/// ```
 ///
 /// Notice that `NonNull<T>` has a `From` instance for `&T`. However, this does
 /// not change the fact that mutating through a (pointer derived from a) shared