diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 5601621f1408e..7a5e400b313dc 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -730,7 +730,11 @@ impl *const T { let pointee_size = size_of::(); 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) } + let offset = unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }; + // SAFETY: the safety contract guarantees that the pointers differ by at most + // `isize::MAX` bytes, so the result cannot be larger than `isize::MAX` elements. + unsafe { intrinsics::assume(offset <= isize::MAX as usize) }; + offset } /// Calculates the distance between two pointers within the same allocation, *where it's known that diff --git a/tests/codegen-llvm/intrinsics/offset_from.rs b/tests/codegen-llvm/intrinsics/offset_from.rs index ef1a77ef184c5..5c317ed031b76 100644 --- a/tests/codegen-llvm/intrinsics/offset_from.rs +++ b/tests/codegen-llvm/intrinsics/offset_from.rs @@ -7,6 +7,7 @@ //! Basic optimizations are enabled because otherwise `x86_64-gnu-nopt` had an alloca. //! Uses a type with non-power-of-two size to avoid normalizations to shifts. +use std::convert::TryFrom; use std::intrinsics::*; type RGB = [u8; 3]; @@ -34,3 +35,12 @@ pub unsafe fn offset_from_unsigned_odd_size(a: *const RGB, b: *const RGB) -> usi // CHECK-NEXT: ret i64 ptr_offset_from_unsigned(a, b) } + +// CHECK-LABEL: @offset_from_unsigned_u8_fits_isize +#[no_mangle] +pub unsafe fn offset_from_unsigned_u8_fits_isize(a: *const u8, b: *const u8) -> isize { + // CHECK-NOT: unwrap_failed + // CHECK-NOT: br i1 + // CHECK: ret i64 + isize::try_from(a.offset_from_unsigned(b)).unwrap() +}