From 72b71710318e2da2a230f3cc01686b006e85ebe6 Mon Sep 17 00:00:00 2001 From: ltdk Date: Tue, 9 Apr 2024 02:01:21 -0400 Subject: [PATCH 1/2] Add assert_unsafe_precondition to unchecked_{add,sub,neg,mul,shl,shr} methods --- library/core/src/lib.rs | 1 + library/core/src/num/int_macros.rs | 99 +++++++++++++++---- library/core/src/num/mod.rs | 1 + library/core/src/num/uint_macros.rs | 80 ++++++++++++--- library/core/src/ops/index_range.rs | 11 +-- library/core/src/ptr/const_ptr.rs | 3 +- library/core/src/ptr/mut_ptr.rs | 3 +- library/core/src/ptr/non_null.rs | 3 +- library/core/src/slice/index.rs | 5 +- ...l_unsigned_smaller.Inline.panic-abort.diff | 22 ++++- ..._unsigned_smaller.Inline.panic-unwind.diff | 22 ++++- ...d_smaller.PreCodegen.after.panic-abort.mir | 4 + ..._smaller.PreCodegen.after.panic-unwind.mir | 4 + ..._shr_signed_bigger.Inline.panic-abort.diff | 22 ++++- ...shr_signed_bigger.Inline.panic-unwind.diff | 22 ++++- ...ed_bigger.PreCodegen.after.panic-abort.mir | 4 + ...d_bigger.PreCodegen.after.panic-unwind.mir | 4 + ...ecked_shl.PreCodegen.after.panic-abort.mir | 4 + ...cked_shl.PreCodegen.after.panic-unwind.mir | 4 + ...mut_range.PreCodegen.after.panic-abort.mir | 47 ++------- ...ut_range.PreCodegen.after.panic-unwind.mir | 47 ++------- ...ked_range.PreCodegen.after.panic-abort.mir | 35 +------ ...ed_range.PreCodegen.after.panic-unwind.mir | 35 +------ 23 files changed, 289 insertions(+), 193 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index dcf68b36c7a2e..6b3ce47da4148 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -191,6 +191,7 @@ #![feature(str_split_remainder)] #![feature(strict_provenance)] #![feature(ub_checks)] +#![feature(unchecked_neg)] #![feature(unchecked_shifts)] #![feature(utf16_extra)] #![feature(utf16_extra_const)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 77b1039039b1d..b8b4f581a7e63 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -488,9 +488,19 @@ macro_rules! int_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_add`. - unsafe { intrinsics::unchecked_add(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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`, @@ -630,9 +640,19 @@ macro_rules! int_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_sub`. - unsafe { intrinsics::unchecked_sub(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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`, @@ -772,9 +792,19 @@ macro_rules! int_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_mul`. - unsafe { intrinsics::unchecked_mul(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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` @@ -1111,9 +1141,22 @@ macro_rules! int_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_neg(self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_neg`. - unsafe { intrinsics::unchecked_sub(0, self) } + // ICE resolved by #125184 isn't in bootstrap compiler + #[cfg(not(bootstrap))] + { + 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`. @@ -1234,9 +1277,19 @@ macro_rules! int_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_shl`. - unsafe { intrinsics::unchecked_shl(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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 @@ -1323,9 +1376,19 @@ macro_rules! int_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_shr`. - unsafe { intrinsics::unchecked_shr(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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 diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 09a341e4d80ac..ab1ede38979da 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -7,6 +7,7 @@ use crate::hint; use crate::intrinsics; use crate::mem; use crate::str::FromStr; +use crate::ub_checks::assert_unsafe_precondition; // Used because the `?` operator is not allowed in a const context. macro_rules! try_opt { diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 446d0658c1262..141d164de14a2 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -495,9 +495,19 @@ macro_rules! uint_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_add`. - unsafe { intrinsics::unchecked_add(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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`, @@ -677,9 +687,19 @@ macro_rules! uint_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_sub`. - unsafe { intrinsics::unchecked_sub(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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 @@ -763,9 +783,19 @@ macro_rules! uint_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_mul`. - unsafe { intrinsics::unchecked_mul(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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` @@ -1334,9 +1364,19 @@ macro_rules! uint_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_shl`. - unsafe { intrinsics::unchecked_shl(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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` @@ -1423,9 +1463,19 @@ macro_rules! uint_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_shr`. - unsafe { intrinsics::unchecked_shr(self, rhs) } + assert_unsafe_precondition!( + check_language_ub, + 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 diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs index 65bda9177c7be..64214eae377dd 100644 --- a/library/core/src/ops/index_range.rs +++ b/library/core/src/ops/index_range.rs @@ -1,4 +1,3 @@ -use crate::intrinsics::{unchecked_add, unchecked_sub}; use crate::iter::{FusedIterator, TrustedLen}; use crate::num::NonZero; use crate::ub_checks; @@ -46,7 +45,7 @@ impl IndexRange { #[inline] pub const fn len(&self) -> usize { // SAFETY: By invariant, this cannot wrap - unsafe { unchecked_sub(self.end, self.start) } + unsafe { self.end.unchecked_sub(self.start) } } /// # Safety @@ -57,7 +56,7 @@ impl IndexRange { let value = self.start; // 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 } @@ -68,7 +67,7 @@ impl IndexRange { debug_assert!(self.start < self.end); // 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; value } @@ -83,7 +82,7 @@ impl IndexRange { let mid = if n <= self.len() { // SAFETY: We just checked that this will be between start and end, // and thus the addition cannot overflow. - unsafe { unchecked_add(self.start, n) } + unsafe { self.start.unchecked_add(n) } } else { self.end }; @@ -102,7 +101,7 @@ impl IndexRange { let mid = if n <= self.len() { // SAFETY: We just checked that this will be between start and end, // and thus the addition cannot overflow. - unsafe { unchecked_sub(self.end, n) } + unsafe { self.end.unchecked_sub(n) } } else { self.start }; diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index c8065b2e70906..8c02aee8bfb40 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1080,6 +1080,7 @@ impl *const 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")] + #[rustc_allow_const_fn_unstable(unchecked_neg)] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn sub(self, count: usize) -> Self @@ -1093,7 +1094,7 @@ impl *const T { // 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)) } + unsafe { self.offset((count as isize).unchecked_neg()) } } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index c53953400addd..7c685156cbb07 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1224,6 +1224,7 @@ impl *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")] + #[rustc_allow_const_fn_unstable(unchecked_neg)] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn sub(self, count: usize) -> Self @@ -1237,7 +1238,7 @@ impl *mut T { // 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)) } + unsafe { self.offset((count as isize).unchecked_neg()) } } } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 617890cf083b1..aac5c745d635d 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -701,6 +701,7 @@ impl NonNull { #[must_use = "returns a new pointer rather than modifying its argument"] #[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 where T: Sized, @@ -712,7 +713,7 @@ impl NonNull { // 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)) } + unsafe { self.offset((count as isize).unchecked_neg()) } } } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 8d7b6165510a8..98513340a4741 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,7 +1,6 @@ //! Indexing implementations for `[T]`. use crate::intrinsics::const_eval_select; -use crate::intrinsics::unchecked_sub; use crate::ops; use crate::ptr; use crate::ub_checks::assert_unsafe_precondition; @@ -374,7 +373,7 @@ unsafe impl SliceIndex<[T]> for ops::Range { // `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. 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) } } @@ -392,7 +391,7 @@ unsafe impl SliceIndex<[T]> for ops::Range { ); // SAFETY: see comments for `get_unchecked` above. 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) } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff index a624ab78dad15..652e24a5f8ec3 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff @@ -8,6 +8,12 @@ let mut _3: u16; let mut _4: u32; + scope 1 (inlined core::num::::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: { @@ -16,10 +22,20 @@ StorageLive(_4); _4 = _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; -- } -- -- bb1: { ++ StorageLive(_6); ++ StorageLive(_5); ++ _5 = UbChecks(); ++ switchInt(move _5) -> [0: bb2, otherwise: bb1]; + } + + bb1: { ++ _6 = core::num::::unchecked_shl::precondition_check(_4, const core::num::::BITS) -> [return: bb2, unwind unreachable]; ++ } ++ ++ bb2: { ++ StorageDead(_5); + _0 = ShlUnchecked(_3, _4); ++ StorageDead(_6); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff index 81a0a5b39f71d..dbcae605f7699 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff @@ -8,6 +8,12 @@ let mut _3: u16; let mut _4: u32; + scope 1 (inlined core::num::::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: { @@ -16,10 +22,20 @@ StorageLive(_4); _4 = _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue]; -- } -- -- bb1: { ++ StorageLive(_6); ++ StorageLive(_5); ++ _5 = UbChecks(); ++ switchInt(move _5) -> [0: bb2, otherwise: bb1]; + } + + bb1: { ++ _6 = core::num::::unchecked_shl::precondition_check(_4, const core::num::::BITS) -> [return: bb2, unwind unreachable]; ++ } ++ ++ bb2: { ++ StorageDead(_5); + _0 = ShlUnchecked(_3, _4); ++ StorageDead(_6); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir index 9e3802b7501f5..dc27685ee79b2 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir @@ -5,6 +5,10 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { debug b => _2; let mut _0: u16; scope 1 (inlined core::num::::unchecked_shl) { + scope 2 (inlined core::ub_checks::check_language_ub) { + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } } bb0: { diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir index 9e3802b7501f5..dc27685ee79b2 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir @@ -5,6 +5,10 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { debug b => _2; let mut _0: u16; scope 1 (inlined core::num::::unchecked_shl) { + scope 2 (inlined core::ub_checks::check_language_ub) { + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } } bb0: { diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff index a2b3ad4b3babb..88d0621c2877c 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff @@ -8,6 +8,12 @@ let mut _3: i64; let mut _4: u32; + scope 1 (inlined core::num::::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: { @@ -16,10 +22,20 @@ StorageLive(_4); _4 = _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; -- } -- -- bb1: { ++ StorageLive(_6); ++ StorageLive(_5); ++ _5 = UbChecks(); ++ switchInt(move _5) -> [0: bb2, otherwise: bb1]; + } + + bb1: { ++ _6 = core::num::::unchecked_shr::precondition_check(_4, const core::num::::BITS) -> [return: bb2, unwind unreachable]; ++ } ++ ++ bb2: { ++ StorageDead(_5); + _0 = ShrUnchecked(_3, _4); ++ StorageDead(_6); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff index 2ff6b532d61fa..6d4c73cf576a6 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff @@ -8,6 +8,12 @@ let mut _3: i64; let mut _4: u32; + scope 1 (inlined core::num::::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: { @@ -16,10 +22,20 @@ StorageLive(_4); _4 = _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue]; -- } -- -- bb1: { ++ StorageLive(_6); ++ StorageLive(_5); ++ _5 = UbChecks(); ++ switchInt(move _5) -> [0: bb2, otherwise: bb1]; + } + + bb1: { ++ _6 = core::num::::unchecked_shr::precondition_check(_4, const core::num::::BITS) -> [return: bb2, unwind unreachable]; ++ } ++ ++ bb2: { ++ StorageDead(_5); + _0 = ShrUnchecked(_3, _4); ++ StorageDead(_6); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir index f3961982648a8..54f093b87d19f 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir @@ -5,6 +5,10 @@ fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { debug b => _2; let mut _0: i64; scope 1 (inlined core::num::::unchecked_shr) { + scope 2 (inlined core::ub_checks::check_language_ub) { + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } } bb0: { diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir index f3961982648a8..54f093b87d19f 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir @@ -5,6 +5,10 @@ fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { debug b => _2; let mut _0: i64; scope 1 (inlined core::num::::unchecked_shr) { + scope 2 (inlined core::ub_checks::check_language_ub) { + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } } bb0: { diff --git a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-abort.mir index af0a0efc2a664..4edf0d2c47c05 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-abort.mir @@ -8,6 +8,10 @@ fn checked_shl(_1: u32, _2: u32) -> Option { let mut _3: bool; let mut _4: u32; scope 2 (inlined core::num::::unchecked_shl) { + scope 3 (inlined core::ub_checks::check_language_ub) { + scope 4 (inlined core::ub_checks::check_language_ub::runtime) { + } + } } } diff --git a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-unwind.mir index af0a0efc2a664..4edf0d2c47c05 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-unwind.mir @@ -8,6 +8,10 @@ fn checked_shl(_1: u32, _2: u32) -> Option { let mut _3: bool; let mut _4: u32; scope 2 (inlined core::num::::unchecked_shl) { + scope 3 (inlined core::ub_checks::check_language_ub) { + scope 4 (inlined core::ub_checks::check_language_ub::runtime) { + } + } } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 62fe1a8685780..ef3f4a2172005 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -4,47 +4,20 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; - let mut _3: usize; - let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _5: *mut [u32]; - let mut _9: *mut [u32]; - scope 2 (inlined 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::::as_mut_ptr) { - } - scope 7 (inlined std::ptr::mut_ptr::::add) { - } - scope 8 (inlined slice_from_raw_parts_mut::) { - } - } - scope 4 (inlined std::ptr::mut_ptr::::len) { - scope 5 (inlined std::ptr::metadata::<[u32]>) { - } - } - } + let mut _3: *mut [u32]; + let mut _4: *mut [u32]; } bb0: { - _3 = move (_2.0: usize); - _4 = move (_2.1: usize); - StorageLive(_5); - _5 = &raw mut (*_1); - StorageLive(_6); - _6 = SubUnchecked(_4, _3); - StorageLive(_8); - StorageLive(_7); - _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); + StorageLive(_3); + _3 = &raw mut (*_1); + _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + _0 = &mut (*_4); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 62fe1a8685780..9e93a43ac725b 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -4,47 +4,20 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; - let mut _3: usize; - let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _5: *mut [u32]; - let mut _9: *mut [u32]; - scope 2 (inlined 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::::as_mut_ptr) { - } - scope 7 (inlined std::ptr::mut_ptr::::add) { - } - scope 8 (inlined slice_from_raw_parts_mut::) { - } - } - scope 4 (inlined std::ptr::mut_ptr::::len) { - scope 5 (inlined std::ptr::metadata::<[u32]>) { - } - } - } + let mut _3: *mut [u32]; + let mut _4: *mut [u32]; } bb0: { - _3 = move (_2.0: usize); - _4 = move (_2.1: usize); - StorageLive(_5); - _5 = &raw mut (*_1); - StorageLive(_6); - _6 = SubUnchecked(_4, _3); - StorageLive(_8); - StorageLive(_7); - _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); + StorageLive(_3); + _3 = &raw mut (*_1); + _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_3); + _0 = &mut (*_4); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir index 000432ccca7de..650069ee6cea3 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir @@ -4,41 +4,14 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - debug slice => _1; debug index => _2; let mut _0: *const [u32]; - let mut _3: usize; - let mut _4: usize; scope 1 (inlined std::ptr::const_ptr::::get_unchecked::>) { - scope 2 (inlined 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::::as_ptr) { - } - scope 7 (inlined std::ptr::const_ptr::::add) { - } - scope 8 (inlined slice_from_raw_parts::) { - } - } - scope 4 (inlined std::ptr::const_ptr::::len) { - scope 5 (inlined std::ptr::metadata::<[u32]>) { - } - } - } } bb0: { - _3 = move (_2.0: usize); - _4 = move (_2.1: usize); - StorageLive(_5); - _5 = SubUnchecked(_4, _3); - 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); + _0 = as SliceIndex<[u32]>>::get_unchecked(move _2, move _1) -> [return: bb1, unwind unreachable]; + } + + bb1: { return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir index 000432ccca7de..74e8158e75430 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir @@ -4,41 +4,14 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - debug slice => _1; debug index => _2; let mut _0: *const [u32]; - let mut _3: usize; - let mut _4: usize; scope 1 (inlined std::ptr::const_ptr::::get_unchecked::>) { - scope 2 (inlined 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::::as_ptr) { - } - scope 7 (inlined std::ptr::const_ptr::::add) { - } - scope 8 (inlined slice_from_raw_parts::) { - } - } - scope 4 (inlined std::ptr::const_ptr::::len) { - scope 5 (inlined std::ptr::metadata::<[u32]>) { - } - } - } } bb0: { - _3 = move (_2.0: usize); - _4 = move (_2.1: usize); - StorageLive(_5); - _5 = SubUnchecked(_4, _3); - 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); + _0 = as SliceIndex<[u32]>>::get_unchecked(move _2, move _1) -> [return: bb1, unwind continue]; + } + + bb1: { return; } } From 18cb2fa851e13879f182b19883541f66719b714f Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 24 May 2024 21:23:12 -0400 Subject: [PATCH 2/2] Stabilize the runtime of libtest-padding The body of these benchmarks is close to empty but not literally empty. This was making the runtime of the benchmarks (which are compiled without optimizations!) flicker between 9 ns and 10 ns runtime, which changes the padding and breaks the test. Recent changes to the standard library have pushed the runtime closer to 10 ns when unoptimized, which is why we haven't seen such failures before in CI. Contributors can also induce such failures before this PR by running the run-make tests while the system is under heavy load. --- tests/run-make/libtest-padding/tests.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/run-make/libtest-padding/tests.rs b/tests/run-make/libtest-padding/tests.rs index cadf07237e954..97a99b47b5c7c 100644 --- a/tests/run-make/libtest-padding/tests.rs +++ b/tests/run-make/libtest-padding/tests.rs @@ -8,11 +8,7 @@ fn short_test_name() {} fn this_is_a_really_long_test_name() {} #[bench] -fn short_bench_name(b: &mut test::Bencher) { - b.iter(|| 1); -} +fn short_bench_name(b: &mut test::Bencher) {} #[bench] -fn this_is_a_really_long_bench_name(b: &mut test::Bencher) { - b.iter(|| 1); -} +fn this_is_a_really_long_bench_name(b: &mut test::Bencher) {}