summaryrefslogtreecommitdiffstats
path: root/library/core/src/ptr
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src/ptr')
-rw-r--r--library/core/src/ptr/const_ptr.rs23
-rw-r--r--library/core/src/ptr/mod.rs10
-rw-r--r--library/core/src/ptr/mut_ptr.rs41
-rw-r--r--library/core/src/ptr/non_null.rs20
4 files changed, 77 insertions, 17 deletions
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index ee69d89a4..9af8f1228 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -607,7 +607,16 @@ impl<T: ?Sized> *const T {
/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
///
- /// This function is the inverse of [`offset`].
+ /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::<T>() as isize)`,
+ /// except that it has a lot more opportunities for UB, in exchange for the compiler
+ /// better understanding what you are doing.
+ ///
+ /// The primary motivation of this method is for computing the `len` of an array/slice
+ /// of `T` that you are currently representing as a "start" and "end" pointer
+ /// (and "end" is "one past the end" of the array).
+ /// In that case, `end.offset_from(start)` gets you the length of the array.
+ ///
+ /// All of the following safety requirements are trivially satisfied for this usecase.
///
/// [`offset`]: #method.offset
///
@@ -616,7 +625,7 @@ impl<T: ?Sized> *const T {
/// If any of the following conditions are violated, the result is Undefined
/// Behavior:
///
- /// * Both the starting and other pointer must be either in bounds or one
+ /// * Both `self` and `origin` must be either in bounds or one
/// byte past the end of the same [allocated object].
///
/// * Both pointers must be *derived from* a pointer to the same object.
@@ -646,6 +655,14 @@ impl<T: ?Sized> *const T {
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
/// such large allocations either.)
///
+ /// The requirement for pointers to be derived from the same allocated object is primarily
+ /// needed for `const`-compatibility: the distance between pointers into *different* allocated
+ /// objects is not known at compile-time. However, the requirement also exists at
+ /// runtime and may be exploited by optimizations. If you wish to compute the difference between
+ /// pointers that are not guaranteed to be from the same allocation, use `(self as isize -
+ /// origin as isize) / mem::size_of::<T>()`.
+ // FIXME: recommend `addr()` instead of `as usize` once that is stable.
+ ///
/// [`add`]: #method.add
/// [allocated object]: crate::ptr#allocated-object
///
@@ -703,7 +720,7 @@ impl<T: ?Sized> *const T {
/// units of **bytes**.
///
/// This is purely a convenience for casting to a `u8` pointer and
- /// using [offset_from][pointer::offset_from] on it. See that method for
+ /// using [`offset_from`][pointer::offset_from] on it. See that method for
/// documentation and safety requirements.
///
/// For non-`Sized` pointees this operation considers only the data pointers,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 5f094ac4e..d1286a1de 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -698,6 +698,7 @@ where
#[inline(always)]
#[must_use]
#[unstable(feature = "ptr_from_ref", issue = "106116")]
+#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
#[rustc_diagnostic_item = "ptr_from_ref"]
pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
r
@@ -710,7 +711,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
#[inline(always)]
#[must_use]
#[unstable(feature = "ptr_from_ref", issue = "106116")]
-#[rustc_diagnostic_item = "ptr_from_mut"]
+#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
r
}
@@ -795,7 +796,9 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
///
/// Behavior is undefined if any of the following conditions are violated:
///
-/// * Both `x` and `y` must be [valid] for both reads and writes.
+/// * Both `x` and `y` must be [valid] for both reads and writes. They must remain valid even when the
+/// other pointer is written. (This means if the memory ranges overlap, the two pointers must not
+/// be subject to aliasing restrictions relative to each other.)
///
/// * Both `x` and `y` must be properly aligned.
///
@@ -1357,6 +1360,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
+#[rustc_diagnostic_item = "ptr_write"]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn write<T>(dst: *mut T, src: T) {
// Semantically, it would be fine for this to be implemented as a
@@ -1459,6 +1463,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
#[inline]
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
+#[rustc_diagnostic_item = "ptr_write_unaligned"]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
// SAFETY: the caller must guarantee that `dst` is valid for writes.
@@ -1607,6 +1612,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
/// ```
#[inline]
#[stable(feature = "volatile", since = "1.9.0")]
+#[rustc_diagnostic_item = "ptr_write_volatile"]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
// SAFETY: the caller must uphold the safety contract for `volatile_store`.
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 9dbb3f9d3..109c28692 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -109,7 +109,7 @@ impl<T: ?Sized> *mut T {
/// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit
/// coercion.
///
- /// [`cast_mut`]: #method.cast_mut
+ /// [`cast_mut`]: pointer::cast_mut
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
#[rustc_diagnostic_item = "ptr_cast_const"]
@@ -121,7 +121,7 @@ impl<T: ?Sized> *mut T {
/// Casts a pointer to its raw bits.
///
/// This is equivalent to `as usize`, but is more specific to enhance readability.
- /// The inverse method is [`from_bits`](#method.from_bits-1).
+ /// The inverse method is [`from_bits`](pointer#method.from_bits-1).
///
/// In particular, `*p as usize` and `p as usize` will both compile for
/// pointers to numeric types but do very different things, so using this
@@ -157,7 +157,7 @@ impl<T: ?Sized> *mut T {
/// Creates a pointer from its raw bits.
///
/// This is equivalent to `as *mut T`, but is more specific to enhance readability.
- /// The inverse method is [`to_bits`](#method.to_bits-1).
+ /// The inverse method is [`to_bits`](pointer#method.to_bits-1).
///
/// # Examples
///
@@ -307,7 +307,7 @@ impl<T: ?Sized> *mut T {
///
/// For the mutable counterpart see [`as_mut`].
///
- /// [`as_uninit_ref`]: #method.as_uninit_ref-1
+ /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1
/// [`as_mut`]: #method.as_mut
///
/// # Safety
@@ -373,7 +373,7 @@ impl<T: ?Sized> *mut T {
///
/// For the mutable counterpart see [`as_uninit_mut`].
///
- /// [`as_ref`]: #method.as_ref-1
+ /// [`as_ref`]: pointer#method.as_ref-1
/// [`as_uninit_mut`]: #method.as_uninit_mut
///
/// # Safety
@@ -628,7 +628,7 @@ impl<T: ?Sized> *mut T {
/// For the shared counterpart see [`as_ref`].
///
/// [`as_uninit_mut`]: #method.as_uninit_mut
- /// [`as_ref`]: #method.as_ref-1
+ /// [`as_ref`]: pointer#method.as_ref-1
///
/// # Safety
///
@@ -693,7 +693,7 @@ impl<T: ?Sized> *mut T {
/// For the shared counterpart see [`as_uninit_ref`].
///
/// [`as_mut`]: #method.as_mut
- /// [`as_uninit_ref`]: #method.as_uninit_ref-1
+ /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1
///
/// # Safety
///
@@ -781,16 +781,25 @@ impl<T: ?Sized> *mut T {
/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
///
- /// This function is the inverse of [`offset`].
+ /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::<T>() as isize)`,
+ /// except that it has a lot more opportunities for UB, in exchange for the compiler
+ /// better understanding what you are doing.
///
- /// [`offset`]: #method.offset-1
+ /// The primary motivation of this method is for computing the `len` of an array/slice
+ /// of `T` that you are currently representing as a "start" and "end" pointer
+ /// (and "end" is "one past the end" of the array).
+ /// In that case, `end.offset_from(start)` gets you the length of the array.
+ ///
+ /// All of the following safety requirements are trivially satisfied for this usecase.
+ ///
+ /// [`offset`]: pointer#method.offset-1
///
/// # Safety
///
/// If any of the following conditions are violated, the result is Undefined
/// Behavior:
///
- /// * Both the starting and other pointer must be either in bounds or one
+ /// * Both `self` and `origin` must be either in bounds or one
/// byte past the end of the same [allocated object].
///
/// * Both pointers must be *derived from* a pointer to the same object.
@@ -820,6 +829,14 @@ impl<T: ?Sized> *mut T {
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
/// such large allocations either.)
///
+ /// The requirement for pointers to be derived from the same allocated object is primarily
+ /// needed for `const`-compatibility: the distance between pointers into *different* allocated
+ /// objects is not known at compile-time. However, the requirement also exists at
+ /// runtime and may be exploited by optimizations. If you wish to compute the difference between
+ /// pointers that are not guaranteed to be from the same allocation, use `(self as isize -
+ /// origin as isize) / mem::size_of::<T>()`.
+ // FIXME: recommend `addr()` instead of `as usize` once that is stable.
+ ///
/// [`add`]: #method.add
/// [allocated object]: crate::ptr#allocated-object
///
@@ -875,7 +892,7 @@ impl<T: ?Sized> *mut T {
/// units of **bytes**.
///
/// This is purely a convenience for casting to a `u8` pointer and
- /// using [offset_from][pointer::offset_from] on it. See that method for
+ /// using [`offset_from`][pointer::offset_from] on it. See that method for
/// documentation and safety requirements.
///
/// For non-`Sized` pointees this operation considers only the data pointers,
@@ -2064,7 +2081,7 @@ impl<T> *mut [T] {
///
/// For the mutable counterpart see [`as_uninit_slice_mut`].
///
- /// [`as_ref`]: #method.as_ref-1
+ /// [`as_ref`]: pointer#method.as_ref-1
/// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut
///
/// # Safety
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index e0fd347a0..d5bd54fd5 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -43,9 +43,27 @@ use crate::slice::{self, SliceIndex};
/// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr`
/// is never used for mutation.
///
+/// # Representation
+///
+/// Thanks to the [null pointer optimization],
+/// `NonNull<T>` and `Option<NonNull<T>>`
+/// are guaranteed to have the same size and alignment:
+///
+/// ```
+/// # use std::mem::{size_of, align_of};
+/// use std::ptr::NonNull;
+///
+/// assert_eq!(size_of::<NonNull<i16>>(), size_of::<Option<NonNull<i16>>>());
+/// assert_eq!(align_of::<NonNull<i16>>(), align_of::<Option<NonNull<i16>>>());
+///
+/// assert_eq!(size_of::<NonNull<str>>(), size_of::<Option<NonNull<str>>>());
+/// assert_eq!(align_of::<NonNull<str>>(), align_of::<Option<NonNull<str>>>());
+/// ```
+///
/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
/// [`PhantomData`]: crate::marker::PhantomData
/// [`UnsafeCell<T>`]: crate::cell::UnsafeCell
+/// [null pointer optimization]: crate::option#representation
#[stable(feature = "nonnull", since = "1.25.0")]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
@@ -320,6 +338,7 @@ impl<T: ?Sized> NonNull<T> {
/// ```
#[stable(feature = "nonnull", since = "1.25.0")]
#[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]
+ #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
#[must_use]
#[inline(always)]
pub const fn as_ptr(self) -> *mut T {
@@ -579,6 +598,7 @@ impl<T> NonNull<[T]> {
#[must_use]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
+ #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
pub const fn as_mut_ptr(self) -> *mut T {
self.as_non_null_ptr().as_ptr()
}