diff options
Diffstat (limited to 'library/core')
| -rw-r--r-- | library/core/src/intrinsics.rs | 13 | ||||
| -rw-r--r-- | library/core/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/core/src/ptr/const_ptr.rs | 77 | ||||
| -rw-r--r-- | library/core/src/ptr/mut_ptr.rs | 72 | ||||
| -rw-r--r-- | library/core/src/slice/raw.rs | 4 |
5 files changed, 165 insertions, 2 deletions
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d1647c38859..88e4262922d 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1903,6 +1903,11 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize; + /// See documentation of `<*const T>::sub_ptr` for details. + #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] + #[cfg(not(bootstrap))] + pub fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize; + /// See documentation of `<*const T>::guaranteed_eq` for details. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -2385,3 +2390,11 @@ where { called_in_const.call_once(arg) } + +/// Bootstrap polyfill +#[cfg(bootstrap)] +pub const unsafe fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize { + // SAFETY: we have stricter preconditions than `ptr_offset_from`, so can + // call it, and its output has to be positive, so we can just cast. + unsafe { ptr_offset_from(ptr, base) as _ } +} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1612aa582ad..d1936b6b566 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -126,6 +126,7 @@ #![feature(const_option)] #![feature(const_option_ext)] #![feature(const_pin)] +#![feature(const_ptr_sub_ptr)] #![feature(const_replace)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_is_null)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 45964c3a444..028adc796e5 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -611,6 +611,83 @@ impl<T: ?Sized> *const T { unsafe { intrinsics::ptr_offset_from(self, origin) } } + /// Calculates the distance between two pointers, *where it's known that + /// `self` is equal to or greater than `origin`*. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`. + /// + /// This computes the same value that [`offset_from`](#method.offset_from) + /// would compute, but with the added precondition that that the offset is + /// guaranteed to be non-negative. This method is equivalent to + /// `usize::from(self.offset_from(origin)).unwrap_unchecked()`, + /// but it provides slightly more information to the optimizer, which can + /// sometimes allow it to optimize slightly better with some backends. + /// + /// This method can be though of as recovering the `count` that was passed + /// to [`add`](#method.add) (or, with the parameters in the other order, + /// to [`sub`](#method.sub)). The following are all equivalent, assuming + /// that their safety preconditions are met: + /// ```rust + /// # #![feature(ptr_sub_ptr)] + /// # unsafe fn blah(ptr: *const i32, origin: *const i32, count: usize) -> bool { + /// ptr.sub_ptr(origin) == count + /// # && + /// origin.add(count) == ptr + /// # && + /// ptr.sub(count) == origin + /// # } + /// ``` + /// + /// # Safety + /// + /// - The distance between the pointers must be non-negative (`self >= origin`) + /// + /// - *All* the safety conditions of [`offset_from`](#method.offset_from) + /// apply to this method as well; see it for the full details. + /// + /// Importantly, despite the return type of this method being able to represent + /// a larger offset, it's still *not permitted* to pass pointers which differ + /// by more than `isize::MAX` *bytes*. As such, the result of this method will + /// always be less than or equal to `isize::MAX as usize`. + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_sub_ptr)] + /// + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// unsafe { + /// assert_eq!(ptr2.sub_ptr(ptr1), 2); + /// assert_eq!(ptr1.add(2), ptr2); + /// assert_eq!(ptr2.sub(2), ptr1); + /// assert_eq!(ptr2.sub_ptr(ptr2), 0); + /// } + /// + /// // This would be incorrect, as the pointers are not correctly ordered: + /// // ptr1.offset_from(ptr2) + /// ``` + #[unstable(feature = "ptr_sub_ptr", issue = "95892")] + #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] + #[inline] + pub const unsafe fn sub_ptr(self, origin: *const T) -> usize + where + T: Sized, + { + // SAFETY: The comparison has no side-effects, and the intrinsic + // does this check internally in the CTFE implementation. + unsafe { assert_unsafe_precondition!(self >= origin) }; + + let pointee_size = mem::size_of::<T>(); + assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); + // SAFETY: the caller must uphold the safety contract for `ptr_offset_from_unsigned`. + unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } + } + /// Returns whether two pointers are guaranteed to be equal. /// /// At runtime this function behaves like `self == other`. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index ed80cdc9bf9..1a32dd62dfd 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -787,6 +787,78 @@ impl<T: ?Sized> *mut T { unsafe { (self as *const T).offset_from(origin) } } + /// Calculates the distance between two pointers, *where it's known that + /// `self` is equal to or greater than `origin`*. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`. + /// + /// This computes the same value that [`offset_from`](#method.offset_from) + /// would compute, but with the added precondition that that the offset is + /// guaranteed to be non-negative. This method is equivalent to + /// `usize::from(self.offset_from(origin)).unwrap_unchecked()`, + /// but it provides slightly more information to the optimizer, which can + /// sometimes allow it to optimize slightly better with some backends. + /// + /// This method can be though of as recovering the `count` that was passed + /// to [`add`](#method.add) (or, with the parameters in the other order, + /// to [`sub`](#method.sub)). The following are all equivalent, assuming + /// that their safety preconditions are met: + /// ```rust + /// # #![feature(ptr_sub_ptr)] + /// # unsafe fn blah(ptr: *mut i32, origin: *mut i32, count: usize) -> bool { + /// ptr.sub_ptr(origin) == count + /// # && + /// origin.add(count) == ptr + /// # && + /// ptr.sub(count) == origin + /// # } + /// ``` + /// + /// # Safety + /// + /// - The distance between the pointers must be non-negative (`self >= origin`) + /// + /// - *All* the safety conditions of [`offset_from`](#method.offset_from) + /// apply to this method as well; see it for the full details. + /// + /// Importantly, despite the return type of this method being able to represent + /// a larger offset, it's still *not permitted* to pass pointers which differ + /// by more than `isize::MAX` *bytes*. As such, the result of this method will + /// always be less than or equal to `isize::MAX as usize`. + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_sub_ptr)] + /// + /// let mut a = [0; 5]; + /// let p: *mut i32 = a.as_mut_ptr(); + /// unsafe { + /// let ptr1: *mut i32 = p.add(1); + /// let ptr2: *mut i32 = p.add(3); + /// + /// assert_eq!(ptr2.sub_ptr(ptr1), 2); + /// assert_eq!(ptr1.add(2), ptr2); + /// assert_eq!(ptr2.sub(2), ptr1); + /// assert_eq!(ptr2.sub_ptr(ptr2), 0); + /// } + /// + /// // This would be incorrect, as the pointers are not correctly ordered: + /// // ptr1.offset_from(ptr2) + #[unstable(feature = "ptr_sub_ptr", issue = "95892")] + #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] + #[inline] + pub const unsafe fn sub_ptr(self, origin: *const T) -> usize + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `sub_ptr`. + unsafe { (self as *const T).sub_ptr(origin) } + } + /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 1b88573035d..6bc60b04b5c 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -215,7 +215,7 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T] { #[unstable(feature = "slice_from_ptr_range", issue = "89792")] pub unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_ptr_range`. - unsafe { from_raw_parts(range.start, range.end.offset_from(range.start) as usize) } + unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } } /// Performs the same functionality as [`from_ptr_range`], except that a @@ -265,5 +265,5 @@ pub unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { #[unstable(feature = "slice_from_ptr_range", issue = "89792")] pub unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] { // SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`. - unsafe { from_raw_parts_mut(range.start, range.end.offset_from(range.start) as usize) } + unsafe { from_raw_parts_mut(range.start, range.end.sub_ptr(range.start)) } } |
