Skip to content

Commit 5a7d62b

Browse files
committed
make std::intrinsic functions actually be intrinsics
1 parent 414da5b commit 5a7d62b

12 files changed

+332
-348
lines changed

Diff for: library/core/src/intrinsics/mod.rs

+25-293
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@
6262
#![allow(missing_docs)]
6363

6464
use crate::marker::{DiscriminantKind, Tuple};
65-
use crate::mem::SizedTypeProperties;
66-
use crate::{ptr, ub_checks};
65+
use crate::ptr;
6766

6867
pub mod fallback;
6968
pub mod mir;
@@ -74,6 +73,7 @@ pub mod simd;
7473
#[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))]
7574
use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering};
7675

76+
/// This is an accidentally-stable alias to [`ptr::drop_in_place`]; use that instead.
7777
#[stable(feature = "drop_in_place", since = "1.8.0")]
7878
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
7979
#[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")]
@@ -3336,7 +3336,7 @@ pub const unsafe fn typed_swap_nonoverlapping<T>(x: *mut T, y: *mut T) {
33363336
/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(ub_checks)` means that
33373337
/// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the
33383338
/// user has UB checks disabled, the checks will still get optimized out. This intrinsic is
3339-
/// primarily used by [`ub_checks::assert_unsafe_precondition`].
3339+
/// primarily used by [`crate::ub_checks::assert_unsafe_precondition`].
33403340
#[rustc_intrinsic_const_stable_indirect] // just for UB checks
33413341
#[inline(always)]
33423342
#[rustc_intrinsic]
@@ -3625,306 +3625,38 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
36253625
#[rustc_intrinsic]
36263626
pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(ptr: *const P) -> M;
36273627

3628-
// Some functions are defined here because they accidentally got made
3629-
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
3630-
// (`transmute` also falls into this category, but it cannot be wrapped due to the
3631-
// check that `T` and `U` have the same size.)
3632-
3633-
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
3634-
/// and destination must *not* overlap.
3635-
///
3636-
/// For regions of memory which might overlap, use [`copy`] instead.
3637-
///
3638-
/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
3639-
/// with the source and destination arguments swapped,
3640-
/// and `count` counting the number of `T`s instead of bytes.
3641-
///
3642-
/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
3643-
/// requirements of `T`. The initialization state is preserved exactly.
3644-
///
3645-
/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
3646-
///
3647-
/// # Safety
3648-
///
3649-
/// Behavior is undefined if any of the following conditions are violated:
3650-
///
3651-
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
3652-
///
3653-
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
3654-
///
3655-
/// * Both `src` and `dst` must be properly aligned.
3656-
///
3657-
/// * The region of memory beginning at `src` with a size of `count *
3658-
/// size_of::<T>()` bytes must *not* overlap with the region of memory
3659-
/// beginning at `dst` with the same size.
3660-
///
3661-
/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
3662-
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
3663-
/// in the region beginning at `*src` and the region beginning at `*dst` can
3664-
/// [violate memory safety][read-ownership].
3665-
///
3666-
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
3667-
/// `0`, the pointers must be properly aligned.
3668-
///
3669-
/// [`read`]: crate::ptr::read
3670-
/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
3671-
/// [valid]: crate::ptr#safety
3672-
///
3673-
/// # Examples
3674-
///
3675-
/// Manually implement [`Vec::append`]:
3676-
///
3677-
/// ```
3678-
/// use std::ptr;
3679-
///
3680-
/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
3681-
/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
3682-
/// let src_len = src.len();
3683-
/// let dst_len = dst.len();
3684-
///
3685-
/// // Ensure that `dst` has enough capacity to hold all of `src`.
3686-
/// dst.reserve(src_len);
3687-
///
3688-
/// unsafe {
3689-
/// // The call to add is always safe because `Vec` will never
3690-
/// // allocate more than `isize::MAX` bytes.
3691-
/// let dst_ptr = dst.as_mut_ptr().add(dst_len);
3692-
/// let src_ptr = src.as_ptr();
3693-
///
3694-
/// // Truncate `src` without dropping its contents. We do this first,
3695-
/// // to avoid problems in case something further down panics.
3696-
/// src.set_len(0);
3697-
///
3698-
/// // The two regions cannot overlap because mutable references do
3699-
/// // not alias, and two different vectors cannot own the same
3700-
/// // memory.
3701-
/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
3702-
///
3703-
/// // Notify `dst` that it now holds the contents of `src`.
3704-
/// dst.set_len(dst_len + src_len);
3705-
/// }
3706-
/// }
3707-
///
3708-
/// let mut a = vec!['r'];
3709-
/// let mut b = vec!['u', 's', 't'];
3710-
///
3711-
/// append(&mut a, &mut b);
3712-
///
3713-
/// assert_eq!(a, &['r', 'u', 's', 't']);
3714-
/// assert!(b.is_empty());
3715-
/// ```
3716-
///
3717-
/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
3718-
#[doc(alias = "memcpy")]
3628+
/// This is an accidentally-stable alias to [`ptr::copy_nonoverlapping`]; use that instead.
3629+
// Note (intentionally not in the doc comment): `ptr::copy_nonoverlapping` adds some extra
3630+
// debug assertions; if you are writing compiler tests or code inside the standard library
3631+
// that wants to avoid those debug assertions, directly call this intrinsic instead.
37193632
#[stable(feature = "rust1", since = "1.0.0")]
37203633
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
37213634
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
3722-
#[inline(always)]
3723-
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3724-
#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
3725-
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
3726-
#[rustc_intrinsic_const_stable_indirect]
3727-
#[rustc_nounwind]
3728-
#[rustc_intrinsic]
3729-
const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
3730-
3731-
ub_checks::assert_unsafe_precondition!(
3732-
check_language_ub,
3733-
"ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
3734-
and the specified memory ranges do not overlap",
3735-
(
3736-
src: *const () = src as *const (),
3737-
dst: *mut () = dst as *mut (),
3738-
size: usize = size_of::<T>(),
3739-
align: usize = align_of::<T>(),
3740-
count: usize = count,
3741-
) => {
3742-
let zero_size = count == 0 || size == 0;
3743-
ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
3744-
&& ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
3745-
&& ub_checks::maybe_is_nonoverlapping(src, dst, size, count)
3746-
}
3747-
);
3748-
3749-
// SAFETY: the safety contract for `copy_nonoverlapping` must be
3750-
// upheld by the caller.
3751-
unsafe { copy_nonoverlapping(src, dst, count) }
3752-
}
3635+
#[rustc_nounwind]
3636+
#[rustc_intrinsic]
3637+
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
37533638

3754-
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
3755-
/// and destination may overlap.
3756-
///
3757-
/// If the source and destination will *never* overlap,
3758-
/// [`copy_nonoverlapping`] can be used instead.
3759-
///
3760-
/// `copy` is semantically equivalent to C's [`memmove`], but
3761-
/// with the source and destination arguments swapped,
3762-
/// and `count` counting the number of `T`s instead of bytes.
3763-
/// Copying takes place as if the bytes were copied from `src`
3764-
/// to a temporary array and then copied from the array to `dst`.
3765-
///
3766-
/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
3767-
/// requirements of `T`. The initialization state is preserved exactly.
3768-
///
3769-
/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
3770-
///
3771-
/// # Safety
3772-
///
3773-
/// Behavior is undefined if any of the following conditions are violated:
3774-
///
3775-
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
3776-
///
3777-
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even
3778-
/// when `src` is read for `count * size_of::<T>()` bytes. (This means if the memory ranges
3779-
/// overlap, the `dst` pointer must not be invalidated by `src` reads.)
3780-
///
3781-
/// * Both `src` and `dst` must be properly aligned.
3782-
///
3783-
/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
3784-
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
3785-
/// in the region beginning at `*src` and the region beginning at `*dst` can
3786-
/// [violate memory safety][read-ownership].
3787-
///
3788-
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
3789-
/// `0`, the pointers must be properly aligned.
3790-
///
3791-
/// [`read`]: crate::ptr::read
3792-
/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
3793-
/// [valid]: crate::ptr#safety
3794-
///
3795-
/// # Examples
3796-
///
3797-
/// Efficiently create a Rust vector from an unsafe buffer:
3798-
///
3799-
/// ```
3800-
/// use std::ptr;
3801-
///
3802-
/// /// # Safety
3803-
/// ///
3804-
/// /// * `ptr` must be correctly aligned for its type and non-zero.
3805-
/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
3806-
/// /// * Those elements must not be used after calling this function unless `T: Copy`.
3807-
/// # #[allow(dead_code)]
3808-
/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
3809-
/// let mut dst = Vec::with_capacity(elts);
3810-
///
3811-
/// // SAFETY: Our precondition ensures the source is aligned and valid,
3812-
/// // and `Vec::with_capacity` ensures that we have usable space to write them.
3813-
/// unsafe { ptr::copy(ptr, dst.as_mut_ptr(), elts); }
3814-
///
3815-
/// // SAFETY: We created it with this much capacity earlier,
3816-
/// // and the previous `copy` has initialized these elements.
3817-
/// unsafe { dst.set_len(elts); }
3818-
/// dst
3819-
/// }
3820-
/// ```
3821-
#[doc(alias = "memmove")]
3639+
/// This is an accidentally-stable alias to [`ptr::copy`]; use that instead.
3640+
// Note (intentionally not in the doc comment): `ptr::copy` adds some extra
3641+
// debug assertions; if you are writing compiler tests or code inside the standard library
3642+
// that wants to avoid those debug assertions, directly call this intrinsic instead.
38223643
#[stable(feature = "rust1", since = "1.0.0")]
38233644
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
38243645
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
3825-
#[inline(always)]
3826-
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3827-
#[rustc_diagnostic_item = "ptr_copy"]
3828-
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
3829-
#[rustc_intrinsic_const_stable_indirect]
3830-
#[rustc_nounwind]
3831-
#[rustc_intrinsic]
3832-
const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
3833-
3834-
// SAFETY: the safety contract for `copy` must be upheld by the caller.
3835-
unsafe {
3836-
ub_checks::assert_unsafe_precondition!(
3837-
check_language_ub,
3838-
"ptr::copy requires that both pointer arguments are aligned and non-null",
3839-
(
3840-
src: *const () = src as *const (),
3841-
dst: *mut () = dst as *mut (),
3842-
align: usize = align_of::<T>(),
3843-
zero_size: bool = T::IS_ZST || count == 0,
3844-
) =>
3845-
ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
3846-
&& ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
3847-
);
3848-
copy(src, dst, count)
3849-
}
3850-
}
3646+
#[rustc_nounwind]
3647+
#[rustc_intrinsic]
3648+
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
38513649

3852-
/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
3853-
/// `val`.
3854-
///
3855-
/// `write_bytes` is similar to C's [`memset`], but sets `count *
3856-
/// size_of::<T>()` bytes to `val`.
3857-
///
3858-
/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset
3859-
///
3860-
/// # Safety
3861-
///
3862-
/// Behavior is undefined if any of the following conditions are violated:
3863-
///
3864-
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
3865-
///
3866-
/// * `dst` must be properly aligned.
3867-
///
3868-
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
3869-
/// `0`, the pointer must be properly aligned.
3870-
///
3871-
/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB)
3872-
/// later if the written bytes are not a valid representation of some `T`. For instance, the
3873-
/// following is an **incorrect** use of this function:
3874-
///
3875-
/// ```rust,no_run
3876-
/// unsafe {
3877-
/// let mut value: u8 = 0;
3878-
/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool;
3879-
/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`.
3880-
/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB...
3881-
/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️
3882-
/// }
3883-
/// ```
3884-
///
3885-
/// [valid]: crate::ptr#safety
3886-
///
3887-
/// # Examples
3888-
///
3889-
/// Basic usage:
3890-
///
3891-
/// ```
3892-
/// use std::ptr;
3893-
///
3894-
/// let mut vec = vec![0u32; 4];
3895-
/// unsafe {
3896-
/// let vec_ptr = vec.as_mut_ptr();
3897-
/// ptr::write_bytes(vec_ptr, 0xfe, 2);
3898-
/// }
3899-
/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
3900-
/// ```
3901-
#[doc(alias = "memset")]
3650+
/// This is an accidentally-stable alias to [`ptr::write_bytes`]; use that instead.
3651+
// Note (intentionally not in the doc comment): `ptr::write_bytes` adds some extra
3652+
// debug assertions; if you are writing compiler tests or code inside the standard library
3653+
// that wants to avoid those debug assertions, directly call this intrinsic instead.
39023654
#[stable(feature = "rust1", since = "1.0.0")]
39033655
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
3904-
#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
3905-
#[inline(always)]
3906-
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3907-
#[rustc_diagnostic_item = "ptr_write_bytes"]
3908-
pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
3909-
#[rustc_intrinsic_const_stable_indirect]
3910-
#[rustc_nounwind]
3911-
#[rustc_intrinsic]
3912-
const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
3913-
3914-
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
3915-
unsafe {
3916-
ub_checks::assert_unsafe_precondition!(
3917-
check_language_ub,
3918-
"ptr::write_bytes requires that the destination pointer is aligned and non-null",
3919-
(
3920-
addr: *const () = dst as *const (),
3921-
align: usize = align_of::<T>(),
3922-
zero_size: bool = T::IS_ZST || count == 0,
3923-
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size)
3924-
);
3925-
write_bytes(dst, val, count)
3926-
}
3927-
}
3656+
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
3657+
#[rustc_nounwind]
3658+
#[rustc_intrinsic]
3659+
pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
39283660

39293661
/// Returns the minimum of two `f16` values.
39303662
///

Diff for: library/core/src/mem/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ mod transmutability;
2121
#[unstable(feature = "transmutability", issue = "99571")]
2222
pub use transmutability::{Assume, TransmuteFrom};
2323

24+
// This one has to be a re-export (rather than wrapping the underlying intrinsic) so that we can do
25+
// the special magic "types have equal size" check at the call site.
2426
#[stable(feature = "rust1", since = "1.0.0")]
2527
#[doc(inline)]
2628
pub use crate::intrinsics::transmute;

0 commit comments

Comments
 (0)