Skip to content

Commit bbcaed0

Browse files
committed
Auto merge of rust-lang#79684 - usbalbin:const_copy, r=oli-obk
Make copy[_nonoverlapping] const Constifies * `intrinsics::copy` and `intrinsics::copy_nonoverlapping` * `ptr::read` and `ptr::read_unaligned` * `*const T::read` and `*const T::read_unaligned` * `*mut T::read` and `*mut T::read_unaligned` * `MaybeUninit::assume_init_read`
2 parents d107a87 + 0cea1c9 commit bbcaed0

File tree

12 files changed

+185
-13
lines changed

12 files changed

+185
-13
lines changed

compiler/rustc_mir/src/interpret/intrinsics.rs

+23
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,29 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
322322
let result = Scalar::from_uint(truncated_bits, layout.size);
323323
self.write_scalar(result, dest)?;
324324
}
325+
sym::copy | sym::copy_nonoverlapping => {
326+
let elem_ty = instance.substs.type_at(0);
327+
let elem_layout = self.layout_of(elem_ty)?;
328+
let count = self.read_scalar(args[2])?.to_machine_usize(self)?;
329+
let elem_align = elem_layout.align.abi;
330+
331+
let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| {
332+
err_ub_format!("overflow computing total size of `{}`", intrinsic_name)
333+
})?;
334+
let src = self.read_scalar(args[0])?.check_init()?;
335+
let src = self.memory.check_ptr_access(src, size, elem_align)?;
336+
let dest = self.read_scalar(args[1])?.check_init()?;
337+
let dest = self.memory.check_ptr_access(dest, size, elem_align)?;
338+
339+
if let (Some(src), Some(dest)) = (src, dest) {
340+
self.memory.copy(
341+
src,
342+
dest,
343+
size,
344+
intrinsic_name == sym::copy_nonoverlapping,
345+
)?;
346+
}
347+
}
325348
sym::offset => {
326349
let ptr = self.read_scalar(args[0])?.check_init()?;
327350
let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;

library/core/src/intrinsics.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -1846,20 +1846,22 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
18461846
/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
18471847
#[doc(alias = "memcpy")]
18481848
#[stable(feature = "rust1", since = "1.0.0")]
1849+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")]
18491850
#[inline]
1850-
pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
1851+
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
18511852
extern "rust-intrinsic" {
18521853
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
18531854
}
18541855

1855-
if cfg!(debug_assertions)
1856+
// FIXME: Perform these checks only at run time
1857+
/*if cfg!(debug_assertions)
18561858
&& !(is_aligned_and_not_null(src)
18571859
&& is_aligned_and_not_null(dst)
18581860
&& is_nonoverlapping(src, dst, count))
18591861
{
18601862
// Not panicking to keep codegen impact smaller.
18611863
abort();
1862-
}
1864+
}*/
18631865

18641866
// SAFETY: the safety contract for `copy_nonoverlapping` must be
18651867
// upheld by the caller.
@@ -1928,16 +1930,19 @@ pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
19281930
/// ```
19291931
#[doc(alias = "memmove")]
19301932
#[stable(feature = "rust1", since = "1.0.0")]
1933+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")]
19311934
#[inline]
1932-
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
1935+
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
19331936
extern "rust-intrinsic" {
1937+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")]
19341938
fn copy<T>(src: *const T, dst: *mut T, count: usize);
19351939
}
19361940

1937-
if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
1941+
// FIXME: Perform these checks only at run time
1942+
/*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
19381943
// Not panicking to keep codegen impact smaller.
19391944
abort();
1940-
}
1945+
}*/
19411946

19421947
// SAFETY: the safety contract for `copy` must be upheld by the caller.
19431948
unsafe { copy(src, dst, count) }

library/core/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#![feature(const_assert_type)]
7474
#![feature(const_discriminant)]
7575
#![feature(const_cell_into_inner)]
76+
#![feature(const_intrinsic_copy)]
7677
#![feature(const_checked_int_methods)]
7778
#![feature(const_euclidean_int_methods)]
7879
#![feature(const_float_classify)]
@@ -93,6 +94,7 @@
9394
#![feature(const_precise_live_drops)]
9495
#![feature(const_ptr_offset)]
9596
#![feature(const_ptr_offset_from)]
97+
#![feature(const_ptr_read)]
9698
#![feature(const_raw_ptr_comparison)]
9799
#![feature(const_raw_ptr_deref)]
98100
#![feature(const_slice_from_raw_parts)]

library/core/src/mem/maybe_uninit.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -575,8 +575,9 @@ impl<T> MaybeUninit<T> {
575575
/// // they both get dropped!
576576
/// ```
577577
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
578+
#[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
578579
#[inline(always)]
579-
pub unsafe fn assume_init_read(&self) -> T {
580+
pub const unsafe fn assume_init_read(&self) -> T {
580581
// SAFETY: the caller must guarantee that `self` is initialized.
581582
// Reading from `self.as_ptr()` is safe since `self` should be initialized.
582583
unsafe {

library/core/src/ptr/const_ptr.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -745,8 +745,9 @@ impl<T: ?Sized> *const T {
745745
///
746746
/// [`ptr::read`]: crate::ptr::read()
747747
#[stable(feature = "pointer_methods", since = "1.26.0")]
748+
#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
748749
#[inline]
749-
pub unsafe fn read(self) -> T
750+
pub const unsafe fn read(self) -> T
750751
where
751752
T: Sized,
752753
{
@@ -783,8 +784,9 @@ impl<T: ?Sized> *const T {
783784
///
784785
/// [`ptr::read_unaligned`]: crate::ptr::read_unaligned()
785786
#[stable(feature = "pointer_methods", since = "1.26.0")]
787+
#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
786788
#[inline]
787-
pub unsafe fn read_unaligned(self) -> T
789+
pub const unsafe fn read_unaligned(self) -> T
788790
where
789791
T: Sized,
790792
{

library/core/src/ptr/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,8 @@ pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
685685
/// [valid]: self#safety
686686
#[inline]
687687
#[stable(feature = "rust1", since = "1.0.0")]
688-
pub unsafe fn read<T>(src: *const T) -> T {
688+
#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
689+
pub const unsafe fn read<T>(src: *const T) -> T {
689690
// `copy_nonoverlapping` takes care of debug_assert.
690691
let mut tmp = MaybeUninit::<T>::uninit();
691692
// SAFETY: the caller must guarantee that `src` is valid for reads.
@@ -784,7 +785,8 @@ pub unsafe fn read<T>(src: *const T) -> T {
784785
/// ```
785786
#[inline]
786787
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
787-
pub unsafe fn read_unaligned<T>(src: *const T) -> T {
788+
#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
789+
pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
788790
// `copy_nonoverlapping` takes care of debug_assert.
789791
let mut tmp = MaybeUninit::<T>::uninit();
790792
// SAFETY: the caller must guarantee that `src` is valid for reads.

library/core/src/ptr/mut_ptr.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -852,8 +852,9 @@ impl<T: ?Sized> *mut T {
852852
///
853853
/// [`ptr::read`]: crate::ptr::read()
854854
#[stable(feature = "pointer_methods", since = "1.26.0")]
855+
#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
855856
#[inline]
856-
pub unsafe fn read(self) -> T
857+
pub const unsafe fn read(self) -> T
857858
where
858859
T: Sized,
859860
{
@@ -890,8 +891,9 @@ impl<T: ?Sized> *mut T {
890891
///
891892
/// [`ptr::read_unaligned`]: crate::ptr::read_unaligned()
892893
#[stable(feature = "pointer_methods", since = "1.26.0")]
894+
#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
893895
#[inline]
894-
pub unsafe fn read_unaligned(self) -> T
896+
pub const unsafe fn read_unaligned(self) -> T
895897
where
896898
T: Sized,
897899
{

library/core/tests/const_ptr.rs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Aligned to two bytes
2+
const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x45, 0x67])];
3+
4+
const fn unaligned_ptr() -> *const u16 {
5+
// Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16
6+
unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 }
7+
}
8+
9+
#[test]
10+
fn read() {
11+
use core::ptr;
12+
13+
const FOO: i32 = unsafe { ptr::read(&42 as *const i32) };
14+
assert_eq!(FOO, 42);
15+
16+
const ALIGNED: i32 = unsafe { ptr::read_unaligned(&42 as *const i32) };
17+
assert_eq!(ALIGNED, 42);
18+
19+
const UNALIGNED_PTR: *const u16 = unaligned_ptr();
20+
21+
const UNALIGNED: u16 = unsafe { ptr::read_unaligned(UNALIGNED_PTR) };
22+
assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
23+
}
24+
25+
#[test]
26+
fn const_ptr_read() {
27+
const FOO: i32 = unsafe { (&42 as *const i32).read() };
28+
assert_eq!(FOO, 42);
29+
30+
const ALIGNED: i32 = unsafe { (&42 as *const i32).read_unaligned() };
31+
assert_eq!(ALIGNED, 42);
32+
33+
const UNALIGNED_PTR: *const u16 = unaligned_ptr();
34+
35+
const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
36+
assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
37+
}
38+
39+
#[test]
40+
fn mut_ptr_read() {
41+
const FOO: i32 = unsafe { (&42 as *const i32 as *mut i32).read() };
42+
assert_eq!(FOO, 42);
43+
44+
const ALIGNED: i32 = unsafe { (&42 as *const i32 as *mut i32).read_unaligned() };
45+
assert_eq!(ALIGNED, 42);
46+
47+
const UNALIGNED_PTR: *mut u16 = unaligned_ptr() as *mut u16;
48+
49+
const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
50+
assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
51+
}

library/core/tests/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#![feature(const_assume)]
1414
#![feature(const_cell_into_inner)]
1515
#![feature(const_maybe_uninit_assume_init)]
16+
#![feature(const_ptr_read)]
17+
#![feature(const_ptr_offset)]
1618
#![feature(core_intrinsics)]
1719
#![feature(core_private_bignum)]
1820
#![feature(core_private_diy_float)]
@@ -34,6 +36,7 @@
3436
#![feature(raw)]
3537
#![feature(sort_internals)]
3638
#![feature(slice_partition_at_index)]
39+
#![feature(maybe_uninit_extra)]
3740
#![feature(maybe_uninit_write_slice)]
3841
#![feature(min_specialization)]
3942
#![feature(step_trait)]
@@ -82,6 +85,10 @@ mod cell;
8285
mod char;
8386
mod clone;
8487
mod cmp;
88+
89+
#[cfg(not(bootstrap))]
90+
mod const_ptr;
91+
8592
mod fmt;
8693
mod hash;
8794
mod intrinsics;

library/core/tests/mem.rs

+7
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,10 @@ fn uninit_write_slice_cloned_no_drop() {
267267

268268
forget(src);
269269
}
270+
271+
#[test]
272+
#[cfg(not(bootstrap))]
273+
fn uninit_const_assume_init_read() {
274+
const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() };
275+
assert_eq!(FOO, 42);
276+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// error-pattern: any use of this value will cause an error
2+
3+
#![feature(const_ptr_read)]
4+
#![feature(const_ptr_offset)]
5+
6+
fn main() {
7+
use std::ptr;
8+
9+
const DATA: [u32; 1] = [42];
10+
11+
const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) };
12+
13+
const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
14+
const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
15+
const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
error: any use of this value will cause an error
2+
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
3+
|
4+
LL | unsafe { copy_nonoverlapping(src, dst, count) }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
8+
| inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
9+
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
10+
| inside `_READ` at $DIR/out_of_bounds_read.rs:13:33
11+
|
12+
::: $DIR/out_of_bounds_read.rs:13:5
13+
|
14+
LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
15+
| ------------------------------------------------------
16+
|
17+
= note: `#[deny(const_err)]` on by default
18+
19+
error: any use of this value will cause an error
20+
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
21+
|
22+
LL | unsafe { copy_nonoverlapping(src, dst, count) }
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
| |
25+
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
26+
| inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
27+
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
28+
| inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
29+
| inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39
30+
|
31+
::: $DIR/out_of_bounds_read.rs:14:5
32+
|
33+
LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
34+
| --------------------------------------------------------
35+
36+
error: any use of this value will cause an error
37+
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
38+
|
39+
LL | unsafe { copy_nonoverlapping(src, dst, count) }
40+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
41+
| |
42+
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
43+
| inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
44+
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
45+
| inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
46+
| inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37
47+
|
48+
::: $DIR/out_of_bounds_read.rs:15:5
49+
|
50+
LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
51+
| --------------------------------------------------------------------
52+
53+
error: aborting due to 3 previous errors
54+

0 commit comments

Comments
 (0)