Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

assert_unsafe_precondition cleanup #120888

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@

use crate::cmp::Ordering;
use crate::fmt::{self, Debug, Display};
use crate::intrinsics::is_nonoverlapping;
use crate::intrinsics;
use crate::marker::{PhantomData, Unsize};
use crate::mem;
use crate::mem::{self, size_of};
use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
use crate::ptr::{self, NonNull};

Expand Down Expand Up @@ -435,11 +435,15 @@ impl<T> Cell<T> {
#[inline]
#[stable(feature = "move_cell", since = "1.17.0")]
pub fn swap(&self, other: &Self) {
fn is_nonoverlapping<T>(src: *const T, dst: *const T) -> bool {
intrinsics::is_nonoverlapping(src.cast(), dst.cast(), size_of::<T>(), 1)
}

if ptr::eq(self, other) {
// Swapping wouldn't change anything.
return;
}
if !is_nonoverlapping(self, other, 1) {
if !is_nonoverlapping(self, other) {
// See <https://github.com/rust-lang/rust/issues/80778> for why we need to stop here.
panic!("`Cell::swap` on overlapping non-identical `Cell`s");
}
Expand Down
58 changes: 25 additions & 33 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@

use crate::marker::DiscriminantKind;
use crate::marker::Tuple;
use crate::mem::{self, align_of};
use crate::mem::align_of;

pub mod mir;
pub mod simd;
Expand Down Expand Up @@ -1027,7 +1027,7 @@ extern "rust-intrinsic" {

/// The size of the referenced value in bytes.
///
/// The stabilized version of this intrinsic is [`mem::size_of_val`].
/// The stabilized version of this intrinsic is [`crate::mem::size_of_val`].
#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")]
#[rustc_nounwind]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
Expand Down Expand Up @@ -1107,7 +1107,7 @@ extern "rust-intrinsic" {

/// Moves a value out of scope without running drop glue.
///
/// This exists solely for [`mem::forget_unsized`]; normal `forget` uses
/// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses
/// `ManuallyDrop` instead.
///
/// Note that, unlike most intrinsics, this is safe to call;
Expand Down Expand Up @@ -1233,7 +1233,7 @@ extern "rust-intrinsic" {
/// Depending on what the code is doing, the following alternatives are preferable to
/// pointer-to-integer transmutation:
/// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a
/// type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit].
/// type for that buffer, it can use [`MaybeUninit`][crate::mem::MaybeUninit].
/// - If the code actually wants to work on the address the pointer points to, it can use `as`
/// casts or [`ptr.addr()`][pointer::addr].
///
Expand Down Expand Up @@ -2317,7 +2317,7 @@ extern "rust-intrinsic" {
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// The to-be-stabilized version of this intrinsic is [`mem::variant_count`].
/// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`].
#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
Expand Down Expand Up @@ -2569,6 +2569,19 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
pub fn is_val_statically_known<T: Copy>(arg: T) -> bool;

/// Returns the value of `cfg!(debug_assertions)`, but after monomorphization instead of in
/// macro expansion.
///
/// This always returns `false` in const eval and Miri. The interpreter provides better
/// diagnostics than the checks that this is used to implement. However, this means
/// you should only be using this intrinsic to guard requirements that, if violated,
/// immediately lead to UB. Otherwise, const-eval and Miri will miss out on those
/// checks entirely.
///
/// Since this is evaluated after monomorphization, branching on this value can be used to
/// implement debug assertions that are included in the precompiled standard library, but can
/// be optimized out by builds that monomorphize the standard library code with debug
/// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
#[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
#[rustc_safe_intrinsic]
#[cfg(not(bootstrap))]
Expand Down Expand Up @@ -2597,7 +2610,7 @@ pub(crate) const fn debug_assertions() -> bool {
/// These checks are behind a condition which is evaluated at codegen time, not expansion time like
/// [`debug_assert`]. This means that a standard library built with optimizations and debug
/// assertions disabled will have these checks optimized out of its monomorphizations, but if a
/// a caller of the standard library has debug assertions enabled and monomorphizes an expansion of
/// caller of the standard library has debug assertions enabled and monomorphizes an expansion of
/// this macro, that monomorphization will contain the check.
///
/// Since these checks cannot be optimized out in MIR, some care must be taken in both call and
Expand All @@ -2606,8 +2619,8 @@ pub(crate) const fn debug_assertions() -> bool {
/// combination of properties ensures that the code for the checks is only compiled once, and has a
/// minimal impact on the caller's code size.
///
/// Caller should also introducing any other `let` bindings or any code outside this macro in order
/// to call it. Since the precompiled standard library is built with full debuginfo and these
/// Callers should also avoid introducing any other `let` bindings or any code outside this macro in
/// order to call it. Since the precompiled standard library is built with full debuginfo and these
/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
/// debuginfo to have a measurable compile-time impact on debug builds.
///
Expand Down Expand Up @@ -2659,33 +2672,12 @@ pub(crate) fn is_valid_allocation_size(size: usize, len: usize) -> bool {
len <= max_len
}

pub(crate) fn is_nonoverlapping_mono(
src: *const (),
dst: *const (),
size: usize,
count: usize,
) -> bool {
let src_usize = src.addr();
let dst_usize = dst.addr();
let Some(size) = size.checked_mul(count) else {
crate::panicking::panic_nounwind(
"is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
)
};
let diff = src_usize.abs_diff(dst_usize);
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
// they do not overlap.
diff >= size
}

/// Checks whether the regions of memory starting at `src` and `dst` of size
/// `count * size_of::<T>()` do *not* overlap.
#[inline]
pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
/// `count * size` do *not* overlap.
pub(crate) fn is_nonoverlapping(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
let src_usize = src.addr();
let dst_usize = dst.addr();
let Some(size) = mem::size_of::<T>().checked_mul(count) else {
// Use panic_nounwind instead of Option::expect, so that this function is nounwind.
let Some(size) = size.checked_mul(count) else {
crate::panicking::panic_nounwind(
"is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
)
Expand Down Expand Up @@ -2809,7 +2801,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
) =>
is_aligned_and_not_null(src, align)
&& is_aligned_and_not_null(dst, align)
&& is_nonoverlapping_mono(src, dst, size, count)
&& is_nonoverlapping(src, dst, size, count)
);
copy_nonoverlapping(src, dst, count)
}
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ use crate::cmp::Ordering;
use crate::fmt;
use crate::hash;
use crate::intrinsics::{
self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping_mono,
self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping,
};
use crate::marker::FnPtr;

Expand Down Expand Up @@ -976,7 +976,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
) =>
is_aligned_and_not_null(x, align)
&& is_aligned_and_not_null(y, align)
&& is_nonoverlapping_mono(x, y, size, count)
&& is_nonoverlapping(x, y, size, count)
);
}

Expand Down