@@ -428,19 +428,32 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
428
428
#[ inline]
429
429
#[ rustc_const_unstable( feature = "const_swap" , issue = "83163" ) ]
430
430
pub ( crate ) const unsafe fn swap_nonoverlapping_one < T > ( x : * mut T , y : * mut T ) {
431
- // For types smaller than the block optimization below,
432
- // just swap directly to avoid pessimizing codegen.
433
- if mem:: size_of :: < T > ( ) < 32 {
434
- // SAFETY: the caller must guarantee that `x` and `y` are valid
435
- // for writes, properly aligned, and non-overlapping.
436
- unsafe {
437
- let z = read ( x) ;
438
- copy_nonoverlapping ( y, x, 1 ) ;
439
- write ( y, z) ;
431
+ // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
432
+ // reinterpretation of values as (chunkable) byte arrays, and the loop in the
433
+ // block optimization in `swap_nonoverlapping_bytes` is hard to rewrite back
434
+ // into the (unoptimized) direct swapping implementation, so we disable it.
435
+ // FIXME(eddyb) the block optimization also prevents MIR optimizations from
436
+ // understanding `mem::replace`, `Option::take`, etc. - a better overall
437
+ // solution might be to make `swap_nonoverlapping` into an intrinsic, which
438
+ // a backend can choose to implement using the block optimization, or not.
439
+ #[ cfg( not( target_arch = "spirv" ) ) ]
440
+ {
441
+ // Only apply the block optimization in `swap_nonoverlapping_bytes` for types
442
+ // at least as large as the block size, to avoid pessimizing codegen.
443
+ if mem:: size_of :: < T > ( ) >= 32 {
444
+ // SAFETY: the caller must uphold the safety contract for `swap_nonoverlapping`.
445
+ unsafe { swap_nonoverlapping ( x, y, 1 ) } ;
446
+ return ;
440
447
}
441
- } else {
442
- // SAFETY: the caller must uphold the safety contract for `swap_nonoverlapping`.
443
- unsafe { swap_nonoverlapping ( x, y, 1 ) } ;
448
+ }
449
+
450
+ // Direct swapping, for the cases not going through the block optimization.
451
+ // SAFETY: the caller must guarantee that `x` and `y` are valid
452
+ // for writes, properly aligned, and non-overlapping.
453
+ unsafe {
454
+ let z = read ( x) ;
455
+ copy_nonoverlapping ( y, x, 1 ) ;
456
+ write ( y, z) ;
444
457
}
445
458
}
446
459
@@ -1479,6 +1492,10 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
1479
1492
/// as all other references. This macro can create a raw pointer *without* creating
1480
1493
/// a reference first.
1481
1494
///
1495
+ /// Note, however, that the `expr` in `addr_of!(expr)` is still subject to all
1496
+ /// the usual rules. In particular, `addr_of!(*ptr::null())` is Undefined
1497
+ /// Behavior because it dereferences a NULL pointer.
1498
+ ///
1482
1499
/// # Example
1483
1500
///
1484
1501
/// ```
@@ -1495,6 +1512,10 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
1495
1512
/// let raw_f2 = ptr::addr_of!(packed.f2);
1496
1513
/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
1497
1514
/// ```
1515
+ ///
1516
+ /// See [`addr_of_mut`] for how to create a pointer to unininitialized data.
1517
+ /// Doing that with `addr_of` would not make much sense since one could only
1518
+ /// read the data, and that would be Undefined Behavior.
1498
1519
#[ stable( feature = "raw_ref_macros" , since = "1.51.0" ) ]
1499
1520
#[ rustc_macro_transparency = "semitransparent" ]
1500
1521
#[ allow_internal_unstable( raw_ref_op) ]
@@ -1511,7 +1532,13 @@ pub macro addr_of($place:expr) {
1511
1532
/// as all other references. This macro can create a raw pointer *without* creating
1512
1533
/// a reference first.
1513
1534
///
1514
- /// # Example
1535
+ /// Note, however, that the `expr` in `addr_of_mut!(expr)` is still subject to all
1536
+ /// the usual rules. In particular, `addr_of_mut!(*ptr::null_mut())` is Undefined
1537
+ /// Behavior because it dereferences a NULL pointer.
1538
+ ///
1539
+ /// # Examples
1540
+ ///
1541
+ /// **Creating a pointer to unaligned data:**
1515
1542
///
1516
1543
/// ```
1517
1544
/// use std::ptr;
@@ -1528,6 +1555,23 @@ pub macro addr_of($place:expr) {
1528
1555
/// unsafe { raw_f2.write_unaligned(42); }
1529
1556
/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference.
1530
1557
/// ```
1558
+ ///
1559
+ /// **Creating a pointer to uninitialized data:**
1560
+ ///
1561
+ /// ```rust
1562
+ /// use std::{ptr, mem::MaybeUninit};
1563
+ ///
1564
+ /// struct Demo {
1565
+ /// field: bool,
1566
+ /// }
1567
+ ///
1568
+ /// let mut uninit = MaybeUninit::<Demo>::uninit();
1569
+ /// // `&uninit.as_mut().field` would create a reference to an uninitialized `bool`,
1570
+ /// // and thus be Undefined Behavior!
1571
+ /// let f1_ptr = unsafe { ptr::addr_of_mut!((*uninit.as_mut_ptr()).field) };
1572
+ /// unsafe { f1_ptr.write(true); }
1573
+ /// let init = unsafe { uninit.assume_init() };
1574
+ /// ```
1531
1575
#[ stable( feature = "raw_ref_macros" , since = "1.51.0" ) ]
1532
1576
#[ rustc_macro_transparency = "semitransparent" ]
1533
1577
#[ allow_internal_unstable( raw_ref_op) ]
0 commit comments