Auto merge of #121571 - clarfonthey:unchecked-math-preconditions, r=saethlin

Add assert_unsafe_precondition to unchecked_{add,sub,neg,mul,shl,shr} methods

(Old PR is haunted, opening a new one. See #117494 for previous discussion.)

This ensures that these preconditions are actually checked in debug mode, and hopefully should let people know if they messed up. I've also replaced the calls (I could find) in the code that use these intrinsics directly with those that use these methods, so that the asserts actually apply.

More discussions on people misusing these methods in the tracking issue: https://github.com/rust-lang/rust/issues/85122.
This commit is contained in:
bors 2024-05-25 18:07:32 +00:00
commit 48f00110d0
24 changed files with 291 additions and 199 deletions

View File

@ -191,6 +191,7 @@
#![feature(str_split_remainder)] #![feature(str_split_remainder)]
#![feature(strict_provenance)] #![feature(strict_provenance)]
#![feature(ub_checks)] #![feature(ub_checks)]
#![feature(unchecked_neg)]
#![feature(unchecked_shifts)] #![feature(unchecked_shifts)]
#![feature(utf16_extra)] #![feature(utf16_extra)]
#![feature(utf16_extra_const)] #![feature(utf16_extra_const)]

View File

@ -488,9 +488,19 @@ macro_rules! int_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_add`. check_language_ub,
unsafe { intrinsics::unchecked_add(self, rhs) } concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
(
lhs: $SelfT = self,
rhs: $SelfT = rhs,
) => !lhs.overflowing_add(rhs).1,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_add(self, rhs)
}
} }
/// Checked addition with an unsigned integer. Computes `self + rhs`, /// Checked addition with an unsigned integer. Computes `self + rhs`,
@ -630,9 +640,19 @@ macro_rules! int_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_sub`. check_language_ub,
unsafe { intrinsics::unchecked_sub(self, rhs) } concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
(
lhs: $SelfT = self,
rhs: $SelfT = rhs,
) => !lhs.overflowing_sub(rhs).1,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_sub(self, rhs)
}
} }
/// Checked subtraction with an unsigned integer. Computes `self - rhs`, /// Checked subtraction with an unsigned integer. Computes `self - rhs`,
@ -772,9 +792,19 @@ macro_rules! int_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_mul`. check_language_ub,
unsafe { intrinsics::unchecked_mul(self, rhs) } concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
(
lhs: $SelfT = self,
rhs: $SelfT = rhs,
) => !lhs.overflowing_mul(rhs).1,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_mul(self, rhs)
}
} }
/// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0` /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
@ -1111,9 +1141,22 @@ macro_rules! int_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_neg(self) -> Self { pub const unsafe fn unchecked_neg(self) -> Self {
// SAFETY: the caller must uphold the safety contract for // ICE resolved by #125184 isn't in bootstrap compiler
// `unchecked_neg`. #[cfg(not(bootstrap))]
unsafe { intrinsics::unchecked_sub(0, self) } {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::unchecked_neg cannot overflow"),
(
lhs: $SelfT = self,
) => !lhs.overflowing_neg().1,
);
}
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_sub(0, self)
}
} }
/// Strict negation. Computes `-self`, panicking if `self == MIN`. /// Strict negation. Computes `-self`, panicking if `self == MIN`.
@ -1234,9 +1277,19 @@ macro_rules! int_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_shl`. check_language_ub,
unsafe { intrinsics::unchecked_shl(self, rhs) } concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
(
rhs: u32 = rhs,
bits: u32 = Self::BITS,
) => rhs < bits,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_shl(self, rhs)
}
} }
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
@ -1323,9 +1376,19 @@ macro_rules! int_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_shr`. check_language_ub,
unsafe { intrinsics::unchecked_shr(self, rhs) } concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
(
rhs: u32 = rhs,
bits: u32 = Self::BITS,
) => rhs < bits,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_shr(self, rhs)
}
} }
/// Checked absolute value. Computes `self.abs()`, returning `None` if /// Checked absolute value. Computes `self.abs()`, returning `None` if

View File

@ -7,6 +7,7 @@ use crate::hint;
use crate::intrinsics; use crate::intrinsics;
use crate::mem; use crate::mem;
use crate::str::FromStr; use crate::str::FromStr;
use crate::ub_checks::assert_unsafe_precondition;
// Used because the `?` operator is not allowed in a const context. // Used because the `?` operator is not allowed in a const context.
macro_rules! try_opt { macro_rules! try_opt {

View File

@ -495,9 +495,19 @@ macro_rules! uint_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_add`. check_language_ub,
unsafe { intrinsics::unchecked_add(self, rhs) } concat!(stringify!($SelfT), "::unchecked_add cannot overflow"),
(
lhs: $SelfT = self,
rhs: $SelfT = rhs,
) => !lhs.overflowing_add(rhs).1,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_add(self, rhs)
}
} }
/// Checked addition with a signed integer. Computes `self + rhs`, /// Checked addition with a signed integer. Computes `self + rhs`,
@ -677,9 +687,19 @@ macro_rules! uint_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_sub`. check_language_ub,
unsafe { intrinsics::unchecked_sub(self, rhs) } concat!(stringify!($SelfT), "::unchecked_sub cannot overflow"),
(
lhs: $SelfT = self,
rhs: $SelfT = rhs,
) => !lhs.overflowing_sub(rhs).1,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_sub(self, rhs)
}
} }
/// Checked integer multiplication. Computes `self * rhs`, returning /// Checked integer multiplication. Computes `self * rhs`, returning
@ -763,9 +783,19 @@ macro_rules! uint_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_mul`. check_language_ub,
unsafe { intrinsics::unchecked_mul(self, rhs) } concat!(stringify!($SelfT), "::unchecked_mul cannot overflow"),
(
lhs: $SelfT = self,
rhs: $SelfT = rhs,
) => !lhs.overflowing_mul(rhs).1,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_mul(self, rhs)
}
} }
/// Checked integer division. Computes `self / rhs`, returning `None` /// Checked integer division. Computes `self / rhs`, returning `None`
@ -1334,9 +1364,19 @@ macro_rules! uint_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_shl`. check_language_ub,
unsafe { intrinsics::unchecked_shl(self, rhs) } concat!(stringify!($SelfT), "::unchecked_shl cannot overflow"),
(
rhs: u32 = rhs,
bits: u32 = Self::BITS,
) => rhs < bits,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_shl(self, rhs)
}
} }
/// Checked shift right. Computes `self >> rhs`, returning `None` /// Checked shift right. Computes `self >> rhs`, returning `None`
@ -1423,9 +1463,19 @@ macro_rules! uint_impl {
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
// SAFETY: the caller must uphold the safety contract for assert_unsafe_precondition!(
// `unchecked_shr`. check_language_ub,
unsafe { intrinsics::unchecked_shr(self, rhs) } concat!(stringify!($SelfT), "::unchecked_shr cannot overflow"),
(
rhs: u32 = rhs,
bits: u32 = Self::BITS,
) => rhs < bits,
);
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
intrinsics::unchecked_shr(self, rhs)
}
} }
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if

View File

@ -1,4 +1,3 @@
use crate::intrinsics::{unchecked_add, unchecked_sub};
use crate::iter::{FusedIterator, TrustedLen}; use crate::iter::{FusedIterator, TrustedLen};
use crate::num::NonZero; use crate::num::NonZero;
use crate::ub_checks; use crate::ub_checks;
@ -46,7 +45,7 @@ impl IndexRange {
#[inline] #[inline]
pub const fn len(&self) -> usize { pub const fn len(&self) -> usize {
// SAFETY: By invariant, this cannot wrap // SAFETY: By invariant, this cannot wrap
unsafe { unchecked_sub(self.end, self.start) } unsafe { self.end.unchecked_sub(self.start) }
} }
/// # Safety /// # Safety
@ -57,7 +56,7 @@ impl IndexRange {
let value = self.start; let value = self.start;
// SAFETY: The range isn't empty, so this cannot overflow // SAFETY: The range isn't empty, so this cannot overflow
self.start = unsafe { unchecked_add(value, 1) }; self.start = unsafe { value.unchecked_add(1) };
value value
} }
@ -68,7 +67,7 @@ impl IndexRange {
debug_assert!(self.start < self.end); debug_assert!(self.start < self.end);
// SAFETY: The range isn't empty, so this cannot overflow // SAFETY: The range isn't empty, so this cannot overflow
let value = unsafe { unchecked_sub(self.end, 1) }; let value = unsafe { self.end.unchecked_sub(1) };
self.end = value; self.end = value;
value value
} }
@ -83,7 +82,7 @@ impl IndexRange {
let mid = if n <= self.len() { let mid = if n <= self.len() {
// SAFETY: We just checked that this will be between start and end, // SAFETY: We just checked that this will be between start and end,
// and thus the addition cannot overflow. // and thus the addition cannot overflow.
unsafe { unchecked_add(self.start, n) } unsafe { self.start.unchecked_add(n) }
} else { } else {
self.end self.end
}; };
@ -102,7 +101,7 @@ impl IndexRange {
let mid = if n <= self.len() { let mid = if n <= self.len() {
// SAFETY: We just checked that this will be between start and end, // SAFETY: We just checked that this will be between start and end,
// and thus the addition cannot overflow. // and thus the addition cannot overflow.
unsafe { unchecked_sub(self.end, n) } unsafe { self.end.unchecked_sub(n) }
} else { } else {
self.start self.start
}; };

View File

@ -1080,6 +1080,7 @@ impl<T: ?Sized> *const T {
#[stable(feature = "pointer_methods", since = "1.26.0")] #[stable(feature = "pointer_methods", since = "1.26.0")]
#[must_use = "returns a new pointer rather than modifying its argument"] #[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[rustc_allow_const_fn_unstable(unchecked_neg)]
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub(self, count: usize) -> Self pub const unsafe fn sub(self, count: usize) -> Self
@ -1093,7 +1094,7 @@ impl<T: ?Sized> *const T {
// SAFETY: the caller must uphold the safety contract for `offset`. // SAFETY: the caller must uphold the safety contract for `offset`.
// Because the pointee is *not* a ZST, that means that `count` is // Because the pointee is *not* a ZST, that means that `count` is
// at most `isize::MAX`, and thus the negation cannot overflow. // at most `isize::MAX`, and thus the negation cannot overflow.
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) } unsafe { self.offset((count as isize).unchecked_neg()) }
} }
} }

View File

@ -1224,6 +1224,7 @@ impl<T: ?Sized> *mut T {
#[stable(feature = "pointer_methods", since = "1.26.0")] #[stable(feature = "pointer_methods", since = "1.26.0")]
#[must_use = "returns a new pointer rather than modifying its argument"] #[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[rustc_allow_const_fn_unstable(unchecked_neg)]
#[inline(always)] #[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub(self, count: usize) -> Self pub const unsafe fn sub(self, count: usize) -> Self
@ -1237,7 +1238,7 @@ impl<T: ?Sized> *mut T {
// SAFETY: the caller must uphold the safety contract for `offset`. // SAFETY: the caller must uphold the safety contract for `offset`.
// Because the pointee is *not* a ZST, that means that `count` is // Because the pointee is *not* a ZST, that means that `count` is
// at most `isize::MAX`, and thus the negation cannot overflow. // at most `isize::MAX`, and thus the negation cannot overflow.
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) } unsafe { self.offset((count as isize).unchecked_neg()) }
} }
} }

View File

@ -701,6 +701,7 @@ impl<T: ?Sized> NonNull<T> {
#[must_use = "returns a new pointer rather than modifying its argument"] #[must_use = "returns a new pointer rather than modifying its argument"]
#[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")]
#[rustc_allow_const_fn_unstable(unchecked_neg)]
pub const unsafe fn sub(self, count: usize) -> Self pub const unsafe fn sub(self, count: usize) -> Self
where where
T: Sized, T: Sized,
@ -712,7 +713,7 @@ impl<T: ?Sized> NonNull<T> {
// SAFETY: the caller must uphold the safety contract for `offset`. // SAFETY: the caller must uphold the safety contract for `offset`.
// Because the pointee is *not* a ZST, that means that `count` is // Because the pointee is *not* a ZST, that means that `count` is
// at most `isize::MAX`, and thus the negation cannot overflow. // at most `isize::MAX`, and thus the negation cannot overflow.
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) } unsafe { self.offset((count as isize).unchecked_neg()) }
} }
} }

View File

@ -1,7 +1,6 @@
//! Indexing implementations for `[T]`. //! Indexing implementations for `[T]`.
use crate::intrinsics::const_eval_select; use crate::intrinsics::const_eval_select;
use crate::intrinsics::unchecked_sub;
use crate::ops; use crate::ops;
use crate::ptr; use crate::ptr;
use crate::ub_checks::assert_unsafe_precondition; use crate::ub_checks::assert_unsafe_precondition;
@ -374,7 +373,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
// so the call to `add` is safe and the length calculation cannot overflow. // so the call to `add` is safe and the length calculation cannot overflow.
unsafe { unsafe {
let new_len = unchecked_sub(self.end, self.start); let new_len = self.end.unchecked_sub(self.start);
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len)
} }
} }
@ -392,7 +391,7 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
); );
// SAFETY: see comments for `get_unchecked` above. // SAFETY: see comments for `get_unchecked` above.
unsafe { unsafe {
let new_len = unchecked_sub(self.end, self.start); let new_len = self.end.unchecked_sub(self.start);
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len)
} }
} }

View File

@ -8,6 +8,12 @@
let mut _3: u16; let mut _3: u16;
let mut _4: u32; let mut _4: u32;
+ scope 1 (inlined core::num::<impl u16>::unchecked_shl) { + scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
+ let mut _5: bool;
+ let _6: ();
+ scope 2 (inlined core::ub_checks::check_language_ub) {
+ scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
+ }
+ }
+ } + }
bb0: { bb0: {
@ -16,10 +22,20 @@
StorageLive(_4); StorageLive(_4);
_4 = _2; _4 = _2;
- _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; - _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable];
- } + StorageLive(_6);
- + StorageLive(_5);
- bb1: { + _5 = UbChecks();
+ switchInt(move _5) -> [0: bb2, otherwise: bb1];
}
bb1: {
+ _6 = core::num::<impl u16>::unchecked_shl::precondition_check(_4, const core::num::<impl u16>::BITS) -> [return: bb2, unwind unreachable];
+ }
+
+ bb2: {
+ StorageDead(_5);
+ _0 = ShlUnchecked(_3, _4); + _0 = ShlUnchecked(_3, _4);
+ StorageDead(_6);
StorageDead(_4); StorageDead(_4);
StorageDead(_3); StorageDead(_3);
return; return;

View File

@ -8,6 +8,12 @@
let mut _3: u16; let mut _3: u16;
let mut _4: u32; let mut _4: u32;
+ scope 1 (inlined core::num::<impl u16>::unchecked_shl) { + scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
+ let mut _5: bool;
+ let _6: ();
+ scope 2 (inlined core::ub_checks::check_language_ub) {
+ scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
+ }
+ }
+ } + }
bb0: { bb0: {
@ -16,10 +22,20 @@
StorageLive(_4); StorageLive(_4);
_4 = _2; _4 = _2;
- _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue]; - _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue];
- } + StorageLive(_6);
- + StorageLive(_5);
- bb1: { + _5 = UbChecks();
+ switchInt(move _5) -> [0: bb2, otherwise: bb1];
}
bb1: {
+ _6 = core::num::<impl u16>::unchecked_shl::precondition_check(_4, const core::num::<impl u16>::BITS) -> [return: bb2, unwind unreachable];
+ }
+
+ bb2: {
+ StorageDead(_5);
+ _0 = ShlUnchecked(_3, _4); + _0 = ShlUnchecked(_3, _4);
+ StorageDead(_6);
StorageDead(_4); StorageDead(_4);
StorageDead(_3); StorageDead(_3);
return; return;

View File

@ -5,6 +5,10 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 {
debug b => _2; debug b => _2;
let mut _0: u16; let mut _0: u16;
scope 1 (inlined core::num::<impl u16>::unchecked_shl) { scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
scope 2 (inlined core::ub_checks::check_language_ub) {
scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
} }
bb0: { bb0: {

View File

@ -5,6 +5,10 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 {
debug b => _2; debug b => _2;
let mut _0: u16; let mut _0: u16;
scope 1 (inlined core::num::<impl u16>::unchecked_shl) { scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
scope 2 (inlined core::ub_checks::check_language_ub) {
scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
} }
bb0: { bb0: {

View File

@ -8,6 +8,12 @@
let mut _3: i64; let mut _3: i64;
let mut _4: u32; let mut _4: u32;
+ scope 1 (inlined core::num::<impl i64>::unchecked_shr) { + scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
+ let mut _5: bool;
+ let _6: ();
+ scope 2 (inlined core::ub_checks::check_language_ub) {
+ scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
+ }
+ }
+ } + }
bb0: { bb0: {
@ -16,10 +22,20 @@
StorageLive(_4); StorageLive(_4);
_4 = _2; _4 = _2;
- _0 = core::num::<impl i64>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; - _0 = core::num::<impl i64>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable];
- } + StorageLive(_6);
- + StorageLive(_5);
- bb1: { + _5 = UbChecks();
+ switchInt(move _5) -> [0: bb2, otherwise: bb1];
}
bb1: {
+ _6 = core::num::<impl i64>::unchecked_shr::precondition_check(_4, const core::num::<impl i64>::BITS) -> [return: bb2, unwind unreachable];
+ }
+
+ bb2: {
+ StorageDead(_5);
+ _0 = ShrUnchecked(_3, _4); + _0 = ShrUnchecked(_3, _4);
+ StorageDead(_6);
StorageDead(_4); StorageDead(_4);
StorageDead(_3); StorageDead(_3);
return; return;

View File

@ -8,6 +8,12 @@
let mut _3: i64; let mut _3: i64;
let mut _4: u32; let mut _4: u32;
+ scope 1 (inlined core::num::<impl i64>::unchecked_shr) { + scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
+ let mut _5: bool;
+ let _6: ();
+ scope 2 (inlined core::ub_checks::check_language_ub) {
+ scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
+ }
+ }
+ } + }
bb0: { bb0: {
@ -16,10 +22,20 @@
StorageLive(_4); StorageLive(_4);
_4 = _2; _4 = _2;
- _0 = core::num::<impl i64>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue]; - _0 = core::num::<impl i64>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue];
- } + StorageLive(_6);
- + StorageLive(_5);
- bb1: { + _5 = UbChecks();
+ switchInt(move _5) -> [0: bb2, otherwise: bb1];
}
bb1: {
+ _6 = core::num::<impl i64>::unchecked_shr::precondition_check(_4, const core::num::<impl i64>::BITS) -> [return: bb2, unwind unreachable];
+ }
+
+ bb2: {
+ StorageDead(_5);
+ _0 = ShrUnchecked(_3, _4); + _0 = ShrUnchecked(_3, _4);
+ StorageDead(_6);
StorageDead(_4); StorageDead(_4);
StorageDead(_3); StorageDead(_3);
return; return;

View File

@ -5,6 +5,10 @@ fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 {
debug b => _2; debug b => _2;
let mut _0: i64; let mut _0: i64;
scope 1 (inlined core::num::<impl i64>::unchecked_shr) { scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
scope 2 (inlined core::ub_checks::check_language_ub) {
scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
} }
bb0: { bb0: {

View File

@ -5,6 +5,10 @@ fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 {
debug b => _2; debug b => _2;
let mut _0: i64; let mut _0: i64;
scope 1 (inlined core::num::<impl i64>::unchecked_shr) { scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
scope 2 (inlined core::ub_checks::check_language_ub) {
scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
} }
bb0: { bb0: {

View File

@ -8,6 +8,10 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> {
let mut _3: bool; let mut _3: bool;
let mut _4: u32; let mut _4: u32;
scope 2 (inlined core::num::<impl u32>::unchecked_shl) { scope 2 (inlined core::num::<impl u32>::unchecked_shl) {
scope 3 (inlined core::ub_checks::check_language_ub) {
scope 4 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
} }
} }

View File

@ -8,6 +8,10 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> {
let mut _3: bool; let mut _3: bool;
let mut _4: u32; let mut _4: u32;
scope 2 (inlined core::num::<impl u32>::unchecked_shl) { scope 2 (inlined core::num::<impl u32>::unchecked_shl) {
scope 3 (inlined core::ub_checks::check_language_ub) {
scope 4 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
} }
} }

View File

@ -4,47 +4,20 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
debug slice => _1; debug slice => _1;
debug index => _2; debug index => _2;
let mut _0: &mut [u32]; let mut _0: &mut [u32];
let mut _3: usize;
let mut _4: usize;
scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) { scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
let mut _5: *mut [u32]; let mut _3: *mut [u32];
let mut _9: *mut [u32]; let mut _4: *mut [u32];
scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
let _6: usize;
let mut _7: *mut u32;
let mut _8: *mut u32;
scope 3 {
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) {
}
scope 7 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) {
}
scope 8 (inlined slice_from_raw_parts_mut::<u32>) {
}
}
scope 4 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
scope 5 (inlined std::ptr::metadata::<[u32]>) {
}
}
}
} }
bb0: { bb0: {
_3 = move (_2.0: usize); StorageLive(_3);
_4 = move (_2.1: usize); _3 = &raw mut (*_1);
StorageLive(_5); _4 = <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind unreachable];
_5 = &raw mut (*_1); }
StorageLive(_6);
_6 = SubUnchecked(_4, _3); bb1: {
StorageLive(_8); StorageDead(_3);
StorageLive(_7); _0 = &mut (*_4);
_7 = _5 as *mut u32 (PtrToPtr);
_8 = Offset(_7, _3);
StorageDead(_7);
_9 = *mut [u32] from (_8, _6);
StorageDead(_8);
StorageDead(_6);
StorageDead(_5);
_0 = &mut (*_9);
return; return;
} }
} }

View File

@ -4,47 +4,20 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
debug slice => _1; debug slice => _1;
debug index => _2; debug index => _2;
let mut _0: &mut [u32]; let mut _0: &mut [u32];
let mut _3: usize;
let mut _4: usize;
scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) { scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
let mut _5: *mut [u32]; let mut _3: *mut [u32];
let mut _9: *mut [u32]; let mut _4: *mut [u32];
scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
let _6: usize;
let mut _7: *mut u32;
let mut _8: *mut u32;
scope 3 {
scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) {
}
scope 7 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) {
}
scope 8 (inlined slice_from_raw_parts_mut::<u32>) {
}
}
scope 4 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
scope 5 (inlined std::ptr::metadata::<[u32]>) {
}
}
}
} }
bb0: { bb0: {
_3 = move (_2.0: usize); StorageLive(_3);
_4 = move (_2.1: usize); _3 = &raw mut (*_1);
StorageLive(_5); _4 = <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind continue];
_5 = &raw mut (*_1); }
StorageLive(_6);
_6 = SubUnchecked(_4, _3); bb1: {
StorageLive(_8); StorageDead(_3);
StorageLive(_7); _0 = &mut (*_4);
_7 = _5 as *mut u32 (PtrToPtr);
_8 = Offset(_7, _3);
StorageDead(_7);
_9 = *mut [u32] from (_8, _6);
StorageDead(_8);
StorageDead(_6);
StorageDead(_5);
_0 = &mut (*_9);
return; return;
} }
} }

View File

@ -4,41 +4,14 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
debug slice => _1; debug slice => _1;
debug index => _2; debug index => _2;
let mut _0: *const [u32]; let mut _0: *const [u32];
let mut _3: usize;
let mut _4: usize;
scope 1 (inlined std::ptr::const_ptr::<impl *const [u32]>::get_unchecked::<std::ops::Range<usize>>) { scope 1 (inlined std::ptr::const_ptr::<impl *const [u32]>::get_unchecked::<std::ops::Range<usize>>) {
scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked) {
let _5: usize;
let mut _6: *const u32;
let mut _7: *const u32;
scope 3 {
scope 6 (inlined std::ptr::const_ptr::<impl *const [u32]>::as_ptr) {
}
scope 7 (inlined std::ptr::const_ptr::<impl *const u32>::add) {
}
scope 8 (inlined slice_from_raw_parts::<u32>) {
}
}
scope 4 (inlined std::ptr::const_ptr::<impl *const [u32]>::len) {
scope 5 (inlined std::ptr::metadata::<[u32]>) {
}
}
}
} }
bb0: { bb0: {
_3 = move (_2.0: usize); _0 = <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked(move _2, move _1) -> [return: bb1, unwind unreachable];
_4 = move (_2.1: usize); }
StorageLive(_5);
_5 = SubUnchecked(_4, _3); bb1: {
StorageLive(_7);
StorageLive(_6);
_6 = _1 as *const u32 (PtrToPtr);
_7 = Offset(_6, _3);
StorageDead(_6);
_0 = *const [u32] from (_7, _5);
StorageDead(_7);
StorageDead(_5);
return; return;
} }
} }

View File

@ -4,41 +4,14 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range<usize>) -
debug slice => _1; debug slice => _1;
debug index => _2; debug index => _2;
let mut _0: *const [u32]; let mut _0: *const [u32];
let mut _3: usize;
let mut _4: usize;
scope 1 (inlined std::ptr::const_ptr::<impl *const [u32]>::get_unchecked::<std::ops::Range<usize>>) { scope 1 (inlined std::ptr::const_ptr::<impl *const [u32]>::get_unchecked::<std::ops::Range<usize>>) {
scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked) {
let _5: usize;
let mut _6: *const u32;
let mut _7: *const u32;
scope 3 {
scope 6 (inlined std::ptr::const_ptr::<impl *const [u32]>::as_ptr) {
}
scope 7 (inlined std::ptr::const_ptr::<impl *const u32>::add) {
}
scope 8 (inlined slice_from_raw_parts::<u32>) {
}
}
scope 4 (inlined std::ptr::const_ptr::<impl *const [u32]>::len) {
scope 5 (inlined std::ptr::metadata::<[u32]>) {
}
}
}
} }
bb0: { bb0: {
_3 = move (_2.0: usize); _0 = <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked(move _2, move _1) -> [return: bb1, unwind continue];
_4 = move (_2.1: usize); }
StorageLive(_5);
_5 = SubUnchecked(_4, _3); bb1: {
StorageLive(_7);
StorageLive(_6);
_6 = _1 as *const u32 (PtrToPtr);
_7 = Offset(_6, _3);
StorageDead(_6);
_0 = *const [u32] from (_7, _5);
StorageDead(_7);
StorageDead(_5);
return; return;
} }
} }

View File

@ -8,11 +8,7 @@ fn short_test_name() {}
fn this_is_a_really_long_test_name() {} fn this_is_a_really_long_test_name() {}
#[bench] #[bench]
fn short_bench_name(b: &mut test::Bencher) { fn short_bench_name(b: &mut test::Bencher) {}
b.iter(|| 1);
}
#[bench] #[bench]
fn this_is_a_really_long_bench_name(b: &mut test::Bencher) { fn this_is_a_really_long_bench_name(b: &mut test::Bencher) {}
b.iter(|| 1);
}