Skip to content

Commit 0860ad8

Browse files
committed
Auto merge of rust-lang#148259 - RalfJung:const-ptr-fragment, r=oli-obk
const-eval: fix and re-enable pointer fragment support The pointer fragment support from rust-lang#144081 got disabled due to rust-lang#146291. This brings it back. To fix the issue, the per-byte provenance fragment tracking tracks *both* the provenance and raw address of the full pointer, so we can ensure that only fragments that are truly part of the same pointer are being merged. r? `@oli-obk` Cc `@theemathas` Fixes rust-lang/const-eval#72 again. Also fixes rust-lang#147959. `@traviscross` I assume this won't need another t-lang FCP since it already got FCP'd in rust-lang#144081?
2 parents 1332a23 + 9035059 commit 0860ad8

File tree

2 files changed

+5
-42
lines changed

2 files changed

+5
-42
lines changed

core/src/ptr/mod.rs

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,40 +1352,6 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
13521352
/// assert_eq!(x, [7, 8, 3, 4]);
13531353
/// assert_eq!(y, [1, 2, 9]);
13541354
/// ```
1355-
///
1356-
/// # Const evaluation limitations
1357-
///
1358-
/// If this function is invoked during const-evaluation, the current implementation has a small (and
1359-
/// rarely relevant) limitation: if `count` is at least 2 and the data pointed to by `x` or `y`
1360-
/// contains a pointer that crosses the boundary of two `T`-sized chunks of memory, the function may
1361-
/// fail to evaluate (similar to a panic during const-evaluation). This behavior may change in the
1362-
/// future.
1363-
///
1364-
/// The limitation is illustrated by the following example:
1365-
///
1366-
/// ```
1367-
/// use std::mem::size_of;
1368-
/// use std::ptr;
1369-
///
1370-
/// const { unsafe {
1371-
/// const PTR_SIZE: usize = size_of::<*const i32>();
1372-
/// let mut data1 = [0u8; PTR_SIZE];
1373-
/// let mut data2 = [0u8; PTR_SIZE];
1374-
/// // Store a pointer in `data1`.
1375-
/// data1.as_mut_ptr().cast::<*const i32>().write_unaligned(&42);
1376-
/// // Swap the contents of `data1` and `data2` by swapping `PTR_SIZE` many `u8`-sized chunks.
1377-
/// // This call will fail, because the pointer in `data1` crosses the boundary
1378-
/// // between several of the 1-byte chunks that are being swapped here.
1379-
/// //ptr::swap_nonoverlapping(data1.as_mut_ptr(), data2.as_mut_ptr(), PTR_SIZE);
1380-
/// // Swap the contents of `data1` and `data2` by swapping a single chunk of size
1381-
/// // `[u8; PTR_SIZE]`. That works, as there is no pointer crossing the boundary between
1382-
/// // two chunks.
1383-
/// ptr::swap_nonoverlapping(&mut data1, &mut data2, 1);
1384-
/// // Read the pointer from `data2` and dereference it.
1385-
/// let ptr = data2.as_ptr().cast::<*const i32>().read_unaligned();
1386-
/// assert!(*ptr == 42);
1387-
/// } }
1388-
/// ```
13891355
#[inline]
13901356
#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
13911357
#[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "1.88.0")]
@@ -1414,9 +1380,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
14141380
const_eval_select!(
14151381
@capture[T] { x: *mut T, y: *mut T, count: usize }:
14161382
if const {
1417-
// At compile-time we want to always copy this in chunks of `T`, to ensure that if there
1418-
// are pointers inside `T` we will copy them in one go rather than trying to copy a part
1419-
// of a pointer (which would not work).
1383+
// At compile-time we don't need all the special code below.
14201384
// SAFETY: Same preconditions as this function
14211385
unsafe { swap_nonoverlapping_const(x, y, count) }
14221386
} else {

coretests/tests/ptr.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -945,13 +945,12 @@ fn test_const_swap_ptr() {
945945
assert!(*s1.0.ptr == 666);
946946
assert!(*s2.0.ptr == 1);
947947

948-
// Swap them back, again as an array.
949-
// FIXME(#146291): we should be swapping back at type `u8` but that currently does not work.
948+
// Swap them back, byte-for-byte
950949
unsafe {
951950
ptr::swap_nonoverlapping(
952-
ptr::from_mut(&mut s1).cast::<T>(),
953-
ptr::from_mut(&mut s2).cast::<T>(),
954-
1,
951+
ptr::from_mut(&mut s1).cast::<u8>(),
952+
ptr::from_mut(&mut s2).cast::<u8>(),
953+
size_of::<A>(),
955954
);
956955
}
957956

0 commit comments

Comments
 (0)