Convert many `assert_unsafe_precondition` to `debug_assert_nounwind`

This commit is contained in:
Gary Guo 2023-04-14 01:22:14 +01:00
parent 4ccec4558f
commit 97c1502066
7 changed files with 98 additions and 132 deletions

View File

@ -98,12 +98,13 @@ use crate::intrinsics;
#[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
#[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 unreachable_unchecked() -> ! { 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 // SAFETY: the safety contract for `intrinsics::unreachable` must
// be upheld by the caller. // be upheld by the caller.
unsafe { unsafe { intrinsics::unreachable() }
intrinsics::assert_unsafe_precondition!("hint::unreachable_unchecked must never be reached", () => false);
intrinsics::unreachable()
}
} }
/// Emits a machine instruction to signal the processor that it is running in /// Emits a machine instruction to signal the processor that it is running in

View File

@ -75,12 +75,12 @@ macro_rules! nonzero_integers {
#[must_use] #[must_use]
#[inline] #[inline]
pub const unsafe fn new_unchecked(n: $Int) -> Self { 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. // SAFETY: this is guaranteed to be safe by the caller.
unsafe { unsafe {
core::intrinsics::assert_unsafe_precondition!(
concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument"),
(n: $Int) => n != 0
);
Self(n) Self(n)
} }
} }

View File

@ -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::iter::{FusedIterator, TrustedLen};
use crate::num::NonZeroUsize; use crate::num::NonZeroUsize;
@ -19,13 +19,10 @@ impl IndexRange {
/// - `start <= end` /// - `start <= end`
#[inline] #[inline]
pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self { pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self {
// SAFETY: comparisons on usize are pure crate::panic::debug_assert_nounwind!(
unsafe { start <= end,
assert_unsafe_precondition!( "IndexRange::new_unchecked requires `start <= end`"
"IndexRange::new_unchecked requires `start <= end`", );
(start: usize, end: usize) => start <= end
)
};
IndexRange { start, end } IndexRange { start, end }
} }

View File

@ -1,5 +1,4 @@
use crate::convert::{TryFrom, TryInto}; use crate::convert::{TryFrom, TryInto};
use crate::intrinsics::assert_unsafe_precondition;
use crate::num::NonZeroUsize; use crate::num::NonZeroUsize;
use crate::{cmp, fmt, hash, mem, num}; use crate::{cmp, fmt, hash, mem, num};
@ -77,13 +76,10 @@ impl Alignment {
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline] #[inline]
pub const unsafe fn new_unchecked(align: usize) -> Self { pub const unsafe fn new_unchecked(align: usize) -> Self {
// SAFETY: Precondition passed to the caller. crate::panic::debug_assert_nounwind!(
unsafe { align.is_power_of_two(),
assert_unsafe_precondition!( "Alignment::new_unchecked requires a power of two"
"Alignment::new_unchecked requires a power of two", );
(align: usize) => align.is_power_of_two()
)
};
// SAFETY: By precondition, this must be a power of two, and // SAFETY: By precondition, this must be a power of two, and
// our variants encompass all possible powers of two. // our variants encompass all possible powers of two.

View File

@ -1,9 +1,9 @@
//! Indexing implementations for `[T]`. //! Indexing implementations for `[T]`.
use crate::intrinsics::assert_unsafe_precondition;
use crate::intrinsics::const_eval_select; use crate::intrinsics::const_eval_select;
use crate::intrinsics::unchecked_sub; use crate::intrinsics::unchecked_sub;
use crate::ops; use crate::ops;
use crate::panic::debug_assert_nounwind;
use crate::ptr; use crate::ptr;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -225,31 +225,25 @@ unsafe impl<T> SliceIndex<[T]> for usize {
#[inline] #[inline]
unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { 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 // SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that // cannot be longer than `isize::MAX`. They also guarantee that
// `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. // so the call to `add` is safe.
unsafe { unsafe { slice.as_ptr().add(self) }
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)
}
} }
#[inline] #[inline]
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
let this = self; debug_assert_nounwind!(
// SAFETY: see comments for `get_unchecked` above. self < slice.len(),
unsafe {
assert_unsafe_precondition!(
"slice::get_unchecked_mut requires that the index is within the slice", "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) // SAFETY: see comments for `get_unchecked` above.
} unsafe { slice.as_mut_ptr().add(self) }
} }
#[inline] #[inline]
@ -293,32 +287,25 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
#[inline] #[inline]
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { 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 // SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that // cannot be longer than `isize::MAX`. They also guarantee that
// `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. // so the call to `add` is safe.
unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len()) }
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())
}
} }
#[inline] #[inline]
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
let end = self.end(); debug_assert_nounwind!(
// SAFETY: see comments for `get_unchecked` above. self.end() <= slice.len(),
unsafe {
assert_unsafe_precondition!(
"slice::get_unchecked_mut requires that the index is within the slice", "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()) // SAFETY: see comments for `get_unchecked` above.
} unsafe { ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len()) }
} }
#[inline] #[inline]
@ -369,17 +356,15 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
#[inline] #[inline]
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { 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 // SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that // cannot be longer than `isize::MAX`. They also guarantee that
// `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 {
assert_unsafe_precondition!(
"slice::get_unchecked requires that the range is within the slice",
[T](this: ops::Range<usize>, slice: *const [T]) =>
this.end >= this.start && this.end <= slice.len()
);
let new_len = unchecked_sub(self.end, self.start); let new_len = unchecked_sub(self.end, 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)
} }
@ -387,14 +372,12 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
#[inline] #[inline]
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { 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. // SAFETY: see comments for `get_unchecked` above.
unsafe { unsafe {
assert_unsafe_precondition!(
"slice::get_unchecked_mut requires that the range is within the slice",
[T](this: ops::Range<usize>, slice: *mut [T]) =>
this.end >= this.start && this.end <= slice.len()
);
let new_len = unchecked_sub(self.end, self.start); let new_len = unchecked_sub(self.end, 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,13 +8,14 @@
use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::cmp::Ordering::{self, Equal, Greater, Less};
use crate::fmt; use crate::fmt;
use crate::intrinsics::{assert_unsafe_precondition, exact_div}; use crate::intrinsics::exact_div;
use crate::marker::Copy; use crate::marker::Copy;
use crate::mem::{self, SizedTypeProperties}; use crate::mem::{self, SizedTypeProperties};
use crate::num::NonZeroUsize; use crate::num::NonZeroUsize;
use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds}; use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds};
use crate::option::Option; use crate::option::Option;
use crate::option::Option::{None, Some}; use crate::option::Option::{None, Some};
use crate::panic::debug_assert_nounwind;
use crate::ptr; use crate::ptr;
use crate::result::Result; use crate::result::Result;
use crate::result::Result::{Err, Ok}; use crate::result::Result::{Err, Ok};
@ -929,14 +930,14 @@ impl<T> [T] {
#[unstable(feature = "slice_swap_unchecked", issue = "88539")] #[unstable(feature = "slice_swap_unchecked", issue = "88539")]
#[rustc_const_unstable(feature = "const_swap", issue = "83163")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
let this = self; debug_assert_nounwind!(
let ptr = this.as_mut_ptr(); 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()` // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()`
unsafe { 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)); ptr::swap(ptr.add(a), ptr.add(b));
} }
} }
@ -1269,15 +1270,12 @@ impl<T> [T] {
#[inline] #[inline]
#[must_use] #[must_use]
pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] { pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
let this = self; debug_assert_nounwind!(
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length N != 0 && self.len() % N == 0,
let new_len = unsafe {
assert_unsafe_precondition!(
"slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", "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) // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
}; let new_len = unsafe { exact_div(self.len(), N) };
// SAFETY: We cast a slice of `new_len * N` elements into // SAFETY: We cast a slice of `new_len * N` elements into
// a slice of `new_len` many `N` elements chunks. // a slice of `new_len` many `N` elements chunks.
unsafe { from_raw_parts(self.as_ptr().cast(), new_len) } unsafe { from_raw_parts(self.as_ptr().cast(), new_len) }
@ -1426,15 +1424,12 @@ impl<T> [T] {
#[inline] #[inline]
#[must_use] #[must_use]
pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] { pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
let this = &*self; debug_assert_nounwind!(
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length N != 0 && self.len() % N == 0,
let new_len = unsafe { "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
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) // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
}; let new_len = unsafe { exact_div(self.len(), N) };
// SAFETY: We cast a slice of `new_len * N` elements into // SAFETY: We cast a slice of `new_len * N` elements into
// a slice of `new_len` many `N` elements chunks. // a slice of `new_len` many `N` elements chunks.
unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), new_len) } unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), new_len) }
@ -1967,14 +1962,13 @@ impl<T> [T] {
let len = self.len(); let len = self.len();
let ptr = self.as_ptr(); let ptr = self.as_ptr();
// SAFETY: Caller has to check that `0 <= mid <= self.len()` debug_assert_nounwind!(
unsafe { mid <= len,
assert_unsafe_precondition!(
"slice::split_at_unchecked requires the index to be within the slice", "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))
} // SAFETY: Caller has to check that `0 <= mid <= self.len()`
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. /// Divides one mutable slice into two at an index, without doing bounds checking.
@ -2018,17 +2012,16 @@ impl<T> [T] {
let len = self.len(); let len = self.len();
let ptr = self.as_mut_ptr(); 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()`. // SAFETY: Caller has to check that `0 <= mid <= self.len()`.
// //
// `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference
// is fine. // is fine.
unsafe { unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) }
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))
}
} }
/// Divides one slice into an array and a remainder slice at an index. /// Divides one slice into an array and a remainder slice at an index.

View File

@ -1,8 +1,8 @@
//! Trait implementations for `str`. //! Trait implementations for `str`.
use crate::cmp::Ordering; use crate::cmp::Ordering;
use crate::intrinsics::assert_unsafe_precondition;
use crate::ops; use crate::ops;
use crate::panic::debug_assert_nounwind;
use crate::ptr; use crate::ptr;
use crate::slice::SliceIndex; use crate::slice::SliceIndex;
@ -191,39 +191,35 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
#[inline] #[inline]
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
let slice = slice as *const [u8]; let slice = slice as *const [u8];
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
// which satisfies all the conditions for `add`. debug_assert_nounwind!(
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<usize>, slice: *const [u8]) =>
// We'd like to check that the bounds are on char boundaries, // We'd like to check that the bounds are on char boundaries,
// but there's not really a way to do so without reading // but there's not really a way to do so without reading
// behind the pointer, which has aliasing implications. // behind the pointer, which has aliasing implications.
// It's also not possible to move this check up to // It's also not possible to move this check up to
// `str::get_unchecked` without adding a special function // `str::get_unchecked` without adding a special function
// to `SliceIndex` just for this. // to `SliceIndex` just for this.
this.end >= this.start && this.end <= slice.len() self.end >= self.start && self.end <= slice.len(),
"str::get_unchecked requires that the range is within the string slice",
); );
slice.as_ptr().add(self.start)
}; // SAFETY: the caller guarantees that `self` is in bounds of `slice`
// which satisfies all the conditions for `add`.
let ptr = unsafe { slice.as_ptr().add(self.start) };
let len = self.end - self.start; let len = self.end - self.start;
ptr::slice_from_raw_parts(ptr, len) as *const str ptr::slice_from_raw_parts(ptr, len) as *const str
} }
#[inline] #[inline]
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
let slice = slice as *mut [u8]; let slice = slice as *mut [u8];
// SAFETY: see comments for `get_unchecked`.
let ptr = unsafe { debug_assert_nounwind!(
let this = ops::Range { ..self }; self.end >= self.start && self.end <= slice.len(),
assert_unsafe_precondition!(
"str::get_unchecked_mut requires that the range is within the string slice", "str::get_unchecked_mut requires that the range is within the string slice",
(this: ops::Range<usize>, slice: *mut [u8]) =>
this.end >= this.start && this.end <= slice.len()
); );
slice.as_mut_ptr().add(self.start)
}; // SAFETY: see comments for `get_unchecked`.
let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
let len = self.end - self.start; let len = self.end - self.start;
ptr::slice_from_raw_parts_mut(ptr, len) as *mut str ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
} }