stabilize ptr::swap_nonoverlapping in const
This commit is contained in:
parent
1b8ab72680
commit
9f4abd313d
6 changed files with 46 additions and 11 deletions
|
|
@ -3320,7 +3320,6 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
|
|||
#[inline]
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_intrinsic_const_stable_indirect]
|
||||
#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic
|
||||
pub const unsafe fn typed_swap_nonoverlapping<T>(x: *mut T, y: *mut T) {
|
||||
// SAFETY: The caller provided single non-overlapping items behind
|
||||
// pointers, so swapping them with `count: 1` is fine.
|
||||
|
|
|
|||
|
|
@ -1065,10 +1065,45 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
|||
/// assert_eq!(x, [7, 8, 3, 4]);
|
||||
/// assert_eq!(y, [1, 2, 9]);
|
||||
/// ```
|
||||
///
|
||||
/// # Const evaluation limitations
|
||||
///
|
||||
/// If this function is invoked during const-evaluation, the current implementation has a small (and
|
||||
/// rarely relevant) limitation: if `count` is at least 2 and the data pointed to by `x` or `y`
|
||||
/// contains a pointer that crosses the boundary of two `T`-sized chunks of memory, the function may
|
||||
/// fail to evaluate (similar to a panic during const-evaluation). This behavior may change in the
|
||||
/// future.
|
||||
///
|
||||
/// The limitation is illustrated by the following example:
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem::size_of;
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// const { unsafe {
|
||||
/// const PTR_SIZE: usize = size_of::<*const i32>();
|
||||
/// let mut data1 = [0u8; PTR_SIZE];
|
||||
/// let mut data2 = [0u8; PTR_SIZE];
|
||||
/// // Store a pointer in `data1`.
|
||||
/// data1.as_mut_ptr().cast::<*const i32>().write_unaligned(&42);
|
||||
/// // Swap the contents of `data1` and `data2` by swapping `PTR_SIZE` many `u8`-sized chunks.
|
||||
/// // This call will fail, because the pointer in `data1` crosses the boundary
|
||||
/// // between several of the 1-byte chunks that are being swapped here.
|
||||
/// //ptr::swap_nonoverlapping(data1.as_mut_ptr(), data2.as_mut_ptr(), PTR_SIZE);
|
||||
/// // Swap the contents of `data1` and `data2` by swapping a single chunk of size
|
||||
/// // `[u8; PTR_SIZE]`. That works, as there is no pointer crossing the boundary between
|
||||
/// // two chunks.
|
||||
/// ptr::swap_nonoverlapping(&mut data1, &mut data2, 1);
|
||||
/// // Read the pointer from `data2` and dereference it.
|
||||
/// let ptr = data2.as_ptr().cast::<*const i32>().read_unaligned();
|
||||
/// assert!(*ptr == 42);
|
||||
/// } }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "const_swap_nonoverlapping", issue = "133668")]
|
||||
#[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_diagnostic_item = "ptr_swap_nonoverlapping"]
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)] // both implementations behave the same
|
||||
pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
||||
ub_checks::assert_unsafe_precondition!(
|
||||
check_library_ub,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#![feature(char_max_len)]
|
||||
#![feature(clone_to_uninit)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(const_swap_nonoverlapping)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(core_intrinsics_fallbacks)]
|
||||
|
|
|
|||
|
|
@ -949,6 +949,10 @@ fn test_const_swap_ptr() {
|
|||
// Make sure they still work.
|
||||
assert!(*s1.0.ptr == 1);
|
||||
assert!(*s2.0.ptr == 666);
|
||||
|
||||
// This is where we'd swap again using a `u8` type and a `count` of `size_of::<T>()` if it
|
||||
// were not for the limitation of `swap_nonoverlapping` around pointers crossing multiple
|
||||
// elements.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//@ compile-flags: -Z ui-testing=no
|
||||
|
||||
|
||||
#![feature(const_swap_nonoverlapping)]
|
||||
use std::{
|
||||
mem::{self, MaybeUninit},
|
||||
ptr,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/missing_span_in_backtrace.rs:16:9
|
||||
--> $DIR/missing_span_in_backtrace.rs:14:9
|
||||
|
|
||||
16 | / ptr::swap_nonoverlapping(
|
||||
17 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
|
||||
18 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
|
||||
19 | | mem::size_of::<&i32>(),
|
||||
20 | | );
|
||||
14 | / ptr::swap_nonoverlapping(
|
||||
15 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
|
||||
16 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
|
||||
17 | | mem::size_of::<&i32>(),
|
||||
18 | | );
|
||||
| |_________^ unable to copy parts of a pointer from memory at ALLOC0
|
||||
|
|
||||
note: inside `swap_nonoverlapping::<MaybeUninit<u8>>`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue