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