Skip to content

Commit 646af41

Browse files
authored
Rollup merge of #90081 - woppopo:const_write_bytes, r=oli-obk
Make `intrinsics::write_bytes` const This is required to constify `MaybeUninit::zeroed` and `(*mut T)::write_bytes`. Tracking issue: #86302
2 parents fefeb46 + 89b2e0c commit 646af41

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+24
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
322322
sym::copy => {
323323
self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
324324
}
325+
sym::write_bytes => {
326+
self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?;
327+
}
325328
sym::offset => {
326329
let ptr = self.read_pointer(&args[0])?;
327330
let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
@@ -567,6 +570,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
567570
self.memory.copy(src, align, dst, align, size, nonoverlapping)
568571
}
569572

573+
pub(crate) fn write_bytes_intrinsic(
574+
&mut self,
575+
dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
576+
byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
577+
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
578+
) -> InterpResult<'tcx> {
579+
let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;
580+
581+
let dst = self.read_pointer(&dst)?;
582+
let byte = self.read_scalar(&byte)?.to_u8()?;
583+
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
584+
585+
let len = layout
586+
.size
587+
.checked_mul(count, self)
588+
.ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?;
589+
590+
let bytes = std::iter::repeat(byte).take(len.bytes_usize());
591+
self.memory.write_bytes(dst, bytes)
592+
}
593+
570594
pub(crate) fn raw_eq_intrinsic(
571595
&mut self,
572596
lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,

library/core/src/intrinsics.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -2244,13 +2244,29 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
22442244
/// assert_eq!(*v, 42);
22452245
/// ```
22462246
#[stable(feature = "rust1", since = "1.0.0")]
2247+
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
22472248
#[inline]
2248-
pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
2249+
pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
22492250
extern "rust-intrinsic" {
2251+
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
22502252
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
22512253
}
22522254

2253-
debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
2255+
#[cfg(debug_assertions)]
2256+
fn runtime_check<T>(ptr: *mut T) {
2257+
debug_assert!(
2258+
is_aligned_and_not_null(ptr),
2259+
"attempt to write to unaligned or null pointer"
2260+
);
2261+
}
2262+
#[cfg(debug_assertions)]
2263+
const fn compiletime_check<T>(_ptr: *mut T) {}
2264+
#[cfg(debug_assertions)]
2265+
// SAFETY: runtime debug-assertions are a best-effort basis; it's fine to
2266+
// not do them during compile time
2267+
unsafe {
2268+
const_eval_select((dst,), compiletime_check, runtime_check);
2269+
}
22542270

22552271
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
22562272
unsafe { write_bytes(dst, val, count) }

library/core/tests/intrinsics.rs

+30
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,33 @@ fn test_assume_can_be_in_const_contexts() {
3535
let rs = unsafe { foo(42, 97) };
3636
assert_eq!(rs, 0);
3737
}
38+
39+
#[test]
40+
#[cfg(not(bootstrap))]
41+
const fn test_write_bytes_in_const_contexts() {
42+
use core::intrinsics::write_bytes;
43+
44+
const TEST: [u32; 3] = {
45+
let mut arr = [1u32, 2, 3];
46+
unsafe {
47+
write_bytes(arr.as_mut_ptr(), 0, 2);
48+
}
49+
arr
50+
};
51+
52+
assert!(TEST[0] == 0);
53+
assert!(TEST[1] == 0);
54+
assert!(TEST[2] == 3);
55+
56+
const TEST2: [u32; 3] = {
57+
let mut arr = [1u32, 2, 3];
58+
unsafe {
59+
write_bytes(arr.as_mut_ptr(), 1, 2);
60+
}
61+
arr
62+
};
63+
64+
assert!(TEST2[0] == 16843009);
65+
assert!(TEST2[1] == 16843009);
66+
assert!(TEST2[2] == 3);
67+
}

0 commit comments

Comments
 (0)