]> git.lizzy.rs Git - rust.git/blobdiff - library/core/src/ptr/mut_ptr.rs
stabilize ptr_offset_from
[rust.git] / library / core / src / ptr / mut_ptr.rs
index eeb425de262be96a43649d93f29abfae80029308..f4b28290f3274a26eb6dc9476d226b79d4ba956d 100644 (file)
@@ -12,6 +12,15 @@ impl<T: ?Sized> *mut T {
     /// Therefore, two pointers that are null may still not compare equal to
     /// each other.
     ///
+    /// ## Behavior during const evaluation
+    ///
+    /// When this function is used during const evaluation, it may return `false` for pointers
+    /// that turn out to be null at runtime. Specifically, when a pointer to some memory
+    /// is offset beyond its bounds in such a way that the resulting pointer is null,
+    /// the function will still return `false`. There is no way for CTFE to know
+    /// the absolute position of that memory, so we cannot tell if the pointer is
+    /// null or not.
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -22,11 +31,12 @@ impl<T: ?Sized> *mut T {
     /// assert!(!ptr.is_null());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
     #[inline]
-    pub fn is_null(self) -> bool {
+    pub const fn is_null(self) -> bool {
         // Compare via a cast to a thin pointer, so fat pointers are only
         // considering their "data" part for null-ness.
-        (self as *mut u8) == null_mut()
+        (self as *mut u8).guaranteed_eq(null_mut())
     }
 
     /// Casts to a pointer of another type.
@@ -464,6 +474,9 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     ///   byte past the end of the same allocated object. Note that in Rust,
     ///   every (stack-allocated) variable is considered a separate allocated object.
     ///
+    /// * Both pointers must be *derived from* a pointer to the same object.
+    ///   (See below for an example.)
+    ///
     /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
     ///
     /// * The distance between the pointers, in bytes, must be an exact multiple
@@ -509,65 +522,34 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     ///     assert_eq!(ptr2.offset(-2), ptr1);
     /// }
     /// ```
-    #[unstable(feature = "ptr_offset_from", issue = "41079")]
-    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
-    #[inline]
-    pub const unsafe fn offset_from(self, origin: *const T) -> isize
-    where
-        T: Sized,
-    {
-        // SAFETY: the caller must uphold the safety contract for `offset_from`.
-        unsafe { (self as *const T).offset_from(origin) }
-    }
-
-    /// Calculates the distance between two pointers. The returned value is in
-    /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
-    ///
-    /// If the address different between the two pointers is not a multiple of
-    /// `mem::size_of::<T>()` then the result of the division is rounded towards
-    /// zero.
-    ///
-    /// Though this method is safe for any two pointers, note that its result
-    /// will be mostly useless if the two pointers aren't into the same allocated
-    /// object, for example if they point to two different local variables.
-    ///
-    /// # Panics
     ///
-    /// This function panics if `T` is a zero-sized type.
+    /// *Incorrect* usage:
     ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// #![feature(ptr_wrapping_offset_from)]
+    /// ```rust,no_run
+    /// #![feature(ptr_offset_from)]
     ///
-    /// let mut a = [0; 5];
-    /// let ptr1: *mut i32 = &mut a[1];
-    /// let ptr2: *mut i32 = &mut a[3];
-    /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
-    /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2);
-    /// assert_eq!(ptr1.wrapping_offset(2), ptr2);
-    /// assert_eq!(ptr2.wrapping_offset(-2), ptr1);
-    ///
-    /// let ptr1: *mut i32 = 3 as _;
-    /// let ptr2: *mut i32 = 13 as _;
-    /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
+    /// let ptr1 = Box::into_raw(Box::new(0u8));
+    /// let ptr2 = Box::into_raw(Box::new(1u8));
+    /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize);
+    /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1.
+    /// let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff);
+    /// assert_eq!(ptr2 as usize, ptr2_other as usize);
+    /// // Since ptr2_other and ptr2 are derived from pointers to different objects,
+    /// // computing their offset is undefined behavior, even though
+    /// // they point to the same address!
+    /// unsafe {
+    ///     let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior
+    /// }
     /// ```
-    #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
-    #[rustc_deprecated(
-        since = "1.46.0",
-        reason = "Pointer distances across allocation \
-        boundaries are not typically meaningful. \
-        Use integer subtraction if you really need this."
-    )]
+    #[stable(feature = "ptr_offset_from", since = "1.46.0")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
     #[inline]
-    pub fn wrapping_offset_from(self, origin: *const T) -> isize
+    pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
         T: Sized,
     {
-        #[allow(deprecated_in_future, deprecated)]
-        (self as *const T).wrapping_offset_from(origin)
+        // SAFETY: the caller must uphold the safety contract for `offset_from`.
+        unsafe { (self as *const T).offset_from(origin) }
     }
 
     /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
@@ -817,6 +799,11 @@ pub const fn wrapping_sub(self, count: usize) -> Self
     /// will only affect the pointer part, whereas for (thin) pointers to
     /// sized types, this has the same effect as a simple assignment.
     ///
+    /// The resulting pointer will have provenance of `val`, i.e., for a fat
+    /// pointer, this operation is semantically the same as creating a new
+    /// fat pointer with the data pointer value of `val` but the metadata of
+    /// `self`.
+    ///
     /// # Examples
     ///
     /// This function is primarily useful for allowing byte-wise pointer
@@ -828,13 +815,17 @@ pub const fn wrapping_sub(self, count: usize) -> Self
     /// let mut arr: [i32; 3] = [1, 2, 3];
     /// let mut ptr = &mut arr[0] as *mut dyn Debug;
     /// let thin = ptr as *mut u8;
-    /// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() });
-    /// assert_eq!(unsafe { *(ptr as *mut i32) }, 3);
+    /// unsafe {
+    ///     ptr = ptr.set_ptr_value(thin.add(8));
+    ///     # assert_eq!(*(ptr as *mut i32), 3);
+    ///     println!("{:?}", &*ptr); // will print "3"
+    /// }
     /// ```
     #[unstable(feature = "set_ptr_value", issue = "75091")]
+    #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
-    pub fn set_ptr_value(mut self, val: *mut ()) -> Self {
-        let thin = &mut self as *mut *mut T as *mut *mut ();
+    pub fn set_ptr_value(mut self, val: *mut u8) -> Self {
+        let thin = &mut self as *mut *mut T as *mut *mut u8;
         // SAFETY: In case of a thin pointer, this operations is identical
         // to a simple assignment. In case of a fat pointer, with the current
         // fat pointer layout implementation, the first field of such a