Tell LLVM that the negation in <*const T>::sub cannot overflow

Today it's just `sub` <https://rust.godbolt.org/z/8EzEPnMr5>; with this PR it's `sub nsw`.
This commit is contained in:
Scott McMurray 2023-08-10 23:00:39 -07:00
parent 8e7fd55131
commit ab6e2bc3d0
3 changed files with 58 additions and 5 deletions

View file

@ -1,6 +1,7 @@
use super::*;
use crate::cmp::Ordering::{self, Equal, Greater, Less};
use crate::intrinsics::{self, const_eval_select};
use crate::mem::SizedTypeProperties;
use crate::slice::{self, SliceIndex};
impl<T: ?Sized> *mut T {
@ -1095,14 +1096,23 @@ impl<T: ?Sized> *mut T {
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
// We could always go back to wrapping if unchecked becomes unacceptable
#[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub(self, count: usize) -> Self
where
T: Sized,
{
// SAFETY: the caller must uphold the safety contract for `offset`.
unsafe { self.offset((count as isize).wrapping_neg()) }
if T::IS_ZST {
// Pointer arithmetic does nothing when the pointee is a ZST.
self
} else {
// SAFETY: the caller must uphold the safety contract for `offset`.
// Because the pointee is *not* a ZST, that means that `count` is
// at most `isize::MAX`, and thus the negation cannot overflow.
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
}
}
/// Calculates the offset from a pointer in bytes (convenience for