395
395
#![ allow( clippy:: not_unsafe_ptr_arg_deref) ]
396
396
397
397
use crate :: cmp:: Ordering ;
398
+ use crate :: intrinsics:: const_eval_select;
398
399
use crate :: marker:: FnPtr ;
399
400
use crate :: mem:: { self , MaybeUninit , SizedTypeProperties } ;
400
401
use crate :: { fmt, hash, intrinsics, ub_checks} ;
@@ -1074,25 +1075,6 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
1074
1075
#[ rustc_const_unstable( feature = "const_swap_nonoverlapping" , issue = "133668" ) ]
1075
1076
#[ rustc_diagnostic_item = "ptr_swap_nonoverlapping" ]
1076
1077
pub const unsafe fn swap_nonoverlapping < T > ( x : * mut T , y : * mut T , count : usize ) {
1077
- #[ allow( unused) ]
1078
- macro_rules! attempt_swap_as_chunks {
1079
- ( $ChunkTy: ty) => {
1080
- if mem:: align_of:: <T >( ) >= mem:: align_of:: <$ChunkTy>( )
1081
- && mem:: size_of:: <T >( ) % mem:: size_of:: <$ChunkTy>( ) == 0
1082
- {
1083
- let x: * mut $ChunkTy = x. cast( ) ;
1084
- let y: * mut $ChunkTy = y. cast( ) ;
1085
- let count = count * ( mem:: size_of:: <T >( ) / mem:: size_of:: <$ChunkTy>( ) ) ;
1086
- // SAFETY: these are the same bytes that the caller promised were
1087
- // ok, just typed as `MaybeUninit<ChunkTy>`s instead of as `T`s.
1088
- // The `if` condition above ensures that we're not violating
1089
- // alignment requirements, and that the division is exact so
1090
- // that we don't lose any bytes off the end.
1091
- return unsafe { swap_nonoverlapping_simple_untyped( x, y, count) } ;
1092
- }
1093
- } ;
1094
- }
1095
-
1096
1078
ub_checks:: assert_unsafe_precondition!(
1097
1079
check_language_ub,
1098
1080
"ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \
@@ -1111,19 +1093,48 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
1111
1093
}
1112
1094
) ;
1113
1095
1114
- // Split up the slice into small power-of-two-sized chunks that LLVM is able
1115
- // to vectorize (unless it's a special type with more-than-pointer alignment,
1116
- // because we don't want to pessimize things like slices of SIMD vectors.)
1117
- if mem:: align_of :: < T > ( ) <= mem:: size_of :: < usize > ( )
1118
- && ( !mem:: size_of :: < T > ( ) . is_power_of_two ( )
1119
- || mem:: size_of :: < T > ( ) > mem:: size_of :: < usize > ( ) * 2 )
1120
- {
1121
- attempt_swap_as_chunks ! ( usize ) ;
1122
- attempt_swap_as_chunks ! ( u8 ) ;
1123
- }
1096
+ const_eval_select ! (
1097
+ @capture[ T ] { x: * mut T , y: * mut T , count: usize } :
1098
+ if const {
1099
+ // At compile-time we want to always copy this in chunks of `T`, to ensure that if there
1100
+ // are pointers inside `T` we will copy them in one go rather than trying to copy a part
1101
+ // of a pointer (which would not work).
1102
+ // SAFETY: Same preconditions as this function
1103
+ unsafe { swap_nonoverlapping_simple_untyped( x, y, count) }
1104
+ } else {
1105
+ macro_rules! attempt_swap_as_chunks {
1106
+ ( $ChunkTy : ty) => {
1107
+ if mem:: align_of:: <T >( ) >= mem:: align_of:: <$ChunkTy >( )
1108
+ && mem:: size_of:: <T >( ) % mem:: size_of:: <$ChunkTy >( ) == 0
1109
+ {
1110
+ let x: * mut $ChunkTy = x. cast( ) ;
1111
+ let y: * mut $ChunkTy = y. cast( ) ;
1112
+ let count = count * ( mem:: size_of:: <T >( ) / mem:: size_of:: <$ChunkTy >( ) ) ;
1113
+ // SAFETY: these are the same bytes that the caller promised were
1114
+ // ok, just typed as `MaybeUninit<ChunkTy>`s instead of as `T`s.
1115
+ // The `if` condition above ensures that we're not violating
1116
+ // alignment requirements, and that the division is exact so
1117
+ // that we don't lose any bytes off the end.
1118
+ return unsafe { swap_nonoverlapping_simple_untyped( x, y, count) } ;
1119
+ }
1120
+ } ;
1121
+ }
1122
+
1123
+ // Split up the slice into small power-of-two-sized chunks that LLVM is able
1124
+ // to vectorize (unless it's a special type with more-than-pointer alignment,
1125
+ // because we don't want to pessimize things like slices of SIMD vectors.)
1126
+ if mem:: align_of:: <T >( ) <= mem:: size_of:: <usize >( )
1127
+ && ( !mem:: size_of:: <T >( ) . is_power_of_two( )
1128
+ || mem:: size_of:: <T >( ) > mem:: size_of:: <usize >( ) * 2 )
1129
+ {
1130
+ attempt_swap_as_chunks!( usize ) ;
1131
+ attempt_swap_as_chunks!( u8 ) ;
1132
+ }
1124
1133
1125
- // SAFETY: Same preconditions as this function
1126
- unsafe { swap_nonoverlapping_simple_untyped ( x, y, count) }
1134
+ // SAFETY: Same preconditions as this function
1135
+ unsafe { swap_nonoverlapping_simple_untyped( x, y, count) }
1136
+ }
1137
+ )
1127
1138
}
1128
1139
1129
1140
/// Same behavior and safety conditions as [`swap_nonoverlapping`]
0 commit comments