diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index ff177c70d39..8e23d6bea3b 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -98,12 +98,13 @@ use crate::intrinsics; #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unreachable_unchecked() -> ! { + crate::panic::debug_assert_nounwind!( + false, + "hint::unreachable_unchecked must never be reached" + ); // SAFETY: the safety contract for `intrinsics::unreachable` must // be upheld by the caller. - unsafe { - intrinsics::assert_unsafe_precondition!("hint::unreachable_unchecked must never be reached", () => false); - intrinsics::unreachable() - } + unsafe { intrinsics::unreachable() } } /// Emits a machine instruction to signal the processor that it is running in diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 7f8d673c179..cc94ee280c6 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -75,12 +75,12 @@ macro_rules! nonzero_integers { #[must_use] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { + crate::panic::debug_assert_nounwind!( + n != 0, + concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument") + ); // SAFETY: this is guaranteed to be safe by the caller. unsafe { - core::intrinsics::assert_unsafe_precondition!( - concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument"), - (n: $Int) => n != 0 - ); Self(n) } } diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs index 265022a394e..743799c4b3e 100644 --- a/library/core/src/ops/index_range.rs +++ b/library/core/src/ops/index_range.rs @@ -1,4 +1,4 @@ -use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub}; +use crate::intrinsics::{unchecked_add, unchecked_sub}; use crate::iter::{FusedIterator, TrustedLen}; use crate::num::NonZeroUsize; @@ -19,13 +19,10 @@ impl IndexRange { /// - `start <= end` #[inline] pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self { - // SAFETY: comparisons on usize are pure - unsafe { - assert_unsafe_precondition!( - "IndexRange::new_unchecked requires `start <= end`", - (start: usize, end: usize) => start <= end - ) - }; + crate::panic::debug_assert_nounwind!( + start <= end, + "IndexRange::new_unchecked requires `start <= end`" + ); IndexRange { start, end } } diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index e578d2257f6..ce176e6fc18 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,5 +1,4 @@ use crate::convert::{TryFrom, TryInto}; -use crate::intrinsics::assert_unsafe_precondition; use crate::num::NonZeroUsize; use crate::{cmp, fmt, hash, mem, num}; @@ -77,13 +76,10 @@ impl Alignment { #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] pub const unsafe fn new_unchecked(align: usize) -> Self { - // SAFETY: Precondition passed to the caller. - unsafe { - assert_unsafe_precondition!( - "Alignment::new_unchecked requires a power of two", - (align: usize) => align.is_power_of_two() - ) - }; + crate::panic::debug_assert_nounwind!( + align.is_power_of_two(), + "Alignment::new_unchecked requires a power of two" + ); // SAFETY: By precondition, this must be a power of two, and // our variants encompass all possible powers of two. diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 1da3a87e117..27afd3b8017 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,9 +1,9 @@ //! Indexing implementations for `[T]`. -use crate::intrinsics::assert_unsafe_precondition; use crate::intrinsics::const_eval_select; use crate::intrinsics::unchecked_sub; use crate::ops; +use crate::panic::debug_assert_nounwind; use crate::ptr; #[stable(feature = "rust1", since = "1.0.0")] @@ -225,31 +225,25 @@ unsafe impl SliceIndex<[T]> for usize { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { - let this = self; + debug_assert_nounwind!( + self < slice.len(), + "slice::get_unchecked requires that the index is within the slice", + ); // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. - unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked requires that the index is within the slice", - [T](this: usize, slice: *const [T]) => this < slice.len() - ); - slice.as_ptr().add(self) - } + unsafe { slice.as_ptr().add(self) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { - let this = self; + debug_assert_nounwind!( + self < slice.len(), + "slice::get_unchecked_mut requires that the index is within the slice", + ); // SAFETY: see comments for `get_unchecked` above. - unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked_mut requires that the index is within the slice", - [T](this: usize, slice: *mut [T]) => this < slice.len() - ); - slice.as_mut_ptr().add(self) - } + unsafe { slice.as_mut_ptr().add(self) } } #[inline] @@ -293,32 +287,25 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - let end = self.end(); + debug_assert_nounwind!( + self.end() <= slice.len(), + "slice::get_unchecked requires that the index is within the slice" + ); // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. - - unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked requires that the index is within the slice", - [T](end: usize, slice: *const [T]) => end <= slice.len() - ); - ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len()) - } + unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len()) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - let end = self.end(); + debug_assert_nounwind!( + self.end() <= slice.len(), + "slice::get_unchecked_mut requires that the index is within the slice", + ); // SAFETY: see comments for `get_unchecked` above. - unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked_mut requires that the index is within the slice", - [T](end: usize, slice: *mut [T]) => end <= slice.len() - ); - ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len()) - } + unsafe { ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len()) } } #[inline] @@ -369,17 +356,15 @@ unsafe impl SliceIndex<[T]> for ops::Range { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - let this = ops::Range { ..self }; + debug_assert_nounwind!( + self.end >= self.start && self.end <= slice.len(), + "slice::get_unchecked requires that the range is within the slice", + ); // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `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 { - assert_unsafe_precondition!( - "slice::get_unchecked requires that the range is within the slice", - [T](this: ops::Range, slice: *const [T]) => - this.end >= this.start && this.end <= slice.len() - ); let new_len = unchecked_sub(self.end, self.start); ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) } @@ -387,14 +372,12 @@ unsafe impl SliceIndex<[T]> for ops::Range { #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - let this = ops::Range { ..self }; + debug_assert_nounwind!( + self.end >= self.start && self.end <= slice.len(), + "slice::get_unchecked_mut requires that the range is within the slice", + ); // SAFETY: see comments for `get_unchecked` above. unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked_mut requires that the range is within the slice", - [T](this: ops::Range, slice: *mut [T]) => - this.end >= this.start && this.end <= slice.len() - ); let new_len = unchecked_sub(self.end, self.start); ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 998ece3afa9..65aae8499f3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -8,13 +8,14 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::fmt; -use crate::intrinsics::{assert_unsafe_precondition, exact_div}; +use crate::intrinsics::exact_div; use crate::marker::Copy; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZeroUsize; use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; +use crate::panic::debug_assert_nounwind; use crate::ptr; use crate::result::Result; use crate::result::Result::{Err, Ok}; @@ -929,14 +930,14 @@ impl [T] { #[unstable(feature = "slice_swap_unchecked", issue = "88539")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { - let this = self; - let ptr = this.as_mut_ptr(); + debug_assert_nounwind!( + a < self.len() && b < self.len(), + "slice::swap_unchecked requires that the indices are within the slice", + ); + + let ptr = self.as_mut_ptr(); // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` unsafe { - assert_unsafe_precondition!( - "slice::swap_unchecked requires that the indices are within the slice", - [T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len() - ); ptr::swap(ptr.add(a), ptr.add(b)); } } @@ -1269,15 +1270,12 @@ impl [T] { #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { - let this = self; + debug_assert_nounwind!( + N != 0 && self.len() % N == 0, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length - let new_len = unsafe { - assert_unsafe_precondition!( - "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", - [T](this: &[T], N: usize) => N != 0 && this.len() % N == 0 - ); - exact_div(self.len(), N) - }; + let new_len = unsafe { exact_div(self.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into // a slice of `new_len` many `N` elements chunks. unsafe { from_raw_parts(self.as_ptr().cast(), new_len) } @@ -1426,15 +1424,12 @@ impl [T] { #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { - let this = &*self; + debug_assert_nounwind!( + N != 0 && self.len() % N == 0, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length - let new_len = unsafe { - assert_unsafe_precondition!( - "slice::as_chunks_unchecked_mut requires `N != 0` and the slice to split exactly into `N`-element chunks", - [T](this: &[T], N: usize) => N != 0 && this.len() % N == 0 - ); - exact_div(this.len(), N) - }; + let new_len = unsafe { exact_div(self.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into // a slice of `new_len` many `N` elements chunks. unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), new_len) } @@ -1967,14 +1962,13 @@ impl [T] { let len = self.len(); let ptr = self.as_ptr(); + debug_assert_nounwind!( + mid <= len, + "slice::split_at_unchecked requires the index to be within the slice", + ); + // SAFETY: Caller has to check that `0 <= mid <= self.len()` - unsafe { - assert_unsafe_precondition!( - "slice::split_at_unchecked requires the index to be within the slice", - (mid: usize, len: usize) => mid <= len - ); - (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) - } + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) } } /// Divides one mutable slice into two at an index, without doing bounds checking. @@ -2018,17 +2012,16 @@ impl [T] { let len = self.len(); let ptr = self.as_mut_ptr(); + debug_assert_nounwind!( + mid <= len, + "slice::split_at_mut_unchecked requires the index to be within the slice", + ); + // SAFETY: Caller has to check that `0 <= mid <= self.len()`. // // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference // is fine. - unsafe { - assert_unsafe_precondition!( - "slice::split_at_mut_unchecked requires the index to be within the slice", - (mid: usize, len: usize) => mid <= len - ); - (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) - } + unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } } /// Divides one slice into an array and a remainder slice at an index. diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 16fb1dad723..777ad0d818b 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -1,8 +1,8 @@ //! Trait implementations for `str`. use crate::cmp::Ordering; -use crate::intrinsics::assert_unsafe_precondition; use crate::ops; +use crate::panic::debug_assert_nounwind; use crate::ptr; use crate::slice::SliceIndex; @@ -191,39 +191,35 @@ unsafe impl SliceIndex for ops::Range { #[inline] unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { let slice = slice as *const [u8]; + + debug_assert_nounwind!( + // We'd like to check that the bounds are on char boundaries, + // but there's not really a way to do so without reading + // behind the pointer, which has aliasing implications. + // It's also not possible to move this check up to + // `str::get_unchecked` without adding a special function + // to `SliceIndex` just for this. + self.end >= self.start && self.end <= slice.len(), + "str::get_unchecked requires that the range is within the string slice", + ); + // SAFETY: the caller guarantees that `self` is in bounds of `slice` // which satisfies all the conditions for `add`. - let ptr = unsafe { - let this = ops::Range { ..self }; - assert_unsafe_precondition!( - "str::get_unchecked requires that the range is within the string slice", - (this: ops::Range, slice: *const [u8]) => - // We'd like to check that the bounds are on char boundaries, - // but there's not really a way to do so without reading - // behind the pointer, which has aliasing implications. - // It's also not possible to move this check up to - // `str::get_unchecked` without adding a special function - // to `SliceIndex` just for this. - this.end >= this.start && this.end <= slice.len() - ); - slice.as_ptr().add(self.start) - }; + let ptr = unsafe { slice.as_ptr().add(self.start) }; let len = self.end - self.start; ptr::slice_from_raw_parts(ptr, len) as *const str } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { let slice = slice as *mut [u8]; + + debug_assert_nounwind!( + self.end >= self.start && self.end <= slice.len(), + "str::get_unchecked_mut requires that the range is within the string slice", + ); + // SAFETY: see comments for `get_unchecked`. - let ptr = unsafe { - let this = ops::Range { ..self }; - assert_unsafe_precondition!( - "str::get_unchecked_mut requires that the range is within the string slice", - (this: ops::Range, slice: *mut [u8]) => - this.end >= this.start && this.end <= slice.len() - ); - slice.as_mut_ptr().add(self.start) - }; + let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; let len = self.end - self.start; ptr::slice_from_raw_parts_mut(ptr, len) as *mut str }