diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index c6750c52d16c8..5bf47c3951da2 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -682,7 +682,8 @@ pub unsafe fn uninitialized() -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn swap(x: &mut T, y: &mut T) { +#[rustc_const_unstable(feature = "const_swap", issue = "83163")] +pub const fn swap(x: &mut T, y: &mut T) { // SAFETY: the raw pointers have been created from safe mutable references satisfying all the // constraints on `ptr::swap_nonoverlapping_one` unsafe { @@ -812,7 +813,8 @@ pub fn take(dest: &mut T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] -pub fn replace(dest: &mut T, src: T) -> T { +#[rustc_const_unstable(feature = "const_replace", issue = "83164")] +pub const fn replace(dest: &mut T, src: T) -> T { // SAFETY: We read from `dest` but directly write `src` into it afterwards, // such that the old value is not duplicated. Nothing is dropped and // nothing here can panic. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 6a6cee0911fea..4b81c39ea1d1b 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -430,7 +430,8 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { } #[inline] -pub(crate) unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { +#[rustc_const_unstable(feature = "const_swap", issue = "83163")] +pub(crate) const unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary // reinterpretation of values as (chunkable) byte arrays, and the loop in the // block optimization in `swap_nonoverlapping_bytes` is hard to rewrite back @@ -563,7 +564,8 @@ const unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn replace(dst: *mut T, mut src: T) -> T { +#[rustc_const_unstable(feature = "const_replace", issue = "83164")] +pub const unsafe fn replace(dst: *mut T, mut src: T) -> T { // SAFETY: the caller must guarantee that `dst` is valid to be // cast to a mutable reference (valid for writes, aligned, initialized), // and cannot overlap `src` since `dst` must point to a distinct @@ -869,10 +871,12 @@ pub const unsafe fn read_unaligned(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn write(dst: *mut T, src: T) { +#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] +pub const unsafe fn write(dst: *mut T, src: T) { // We are calling the intrinsics directly to avoid function calls in the generated code // as `intrinsics::copy_nonoverlapping` is a wrapper function. extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } @@ -964,7 +968,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] -#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] +#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] pub const unsafe fn write_unaligned(dst: *mut T, src: T) { // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index a6424041542d9..93ee74719ffa3 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1002,8 +1002,9 @@ impl *mut T { /// /// [`ptr::write`]: crate::ptr::write() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] - pub unsafe fn write(self, val: T) + pub const unsafe fn write(self, val: T) where T: Sized, { @@ -1056,7 +1057,7 @@ impl *mut T { /// /// [`ptr::write_unaligned`]: crate::ptr::write_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] + #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] pub const unsafe fn write_unaligned(self, val: T) where diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs index 4acd059ab03df..152fed803ecdb 100644 --- a/library/core/tests/const_ptr.rs +++ b/library/core/tests/const_ptr.rs @@ -49,3 +49,53 @@ fn mut_ptr_read() { const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); } + +#[test] +fn write() { + use core::ptr; + + const fn write_aligned() -> i32 { + let mut res = 0; + unsafe { + ptr::write(&mut res as *mut _, 42); + } + res + } + const ALIGNED: i32 = write_aligned(); + assert_eq!(ALIGNED, 42); + + const fn write_unaligned() -> [u16; 2] { + let mut two_aligned = [0u16; 2]; + unsafe { + let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); + } + two_aligned + } + const UNALIGNED: [u16; 2] = write_unaligned(); + assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); +} + +#[test] +fn mut_ptr_write() { + const fn aligned() -> i32 { + let mut res = 0; + unsafe { + (&mut res as *mut i32).write(42); + } + res + } + const ALIGNED: i32 = aligned(); + assert_eq!(ALIGNED, 42); + + const fn write_unaligned() -> [u16; 2] { + let mut two_aligned = [0u16; 2]; + unsafe { + let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); + } + two_aligned + } + const UNALIGNED: [u16; 2] = write_unaligned(); + assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); +} diff --git a/src/test/ui/const-ptr/out_of_bounds_read.rs b/src/test/ui/const-ptr/out_of_bounds_read.rs new file mode 100644 index 0000000000000..c45198cc39b08 --- /dev/null +++ b/src/test/ui/const-ptr/out_of_bounds_read.rs @@ -0,0 +1,16 @@ +// error-pattern: evaluation of constant value failed + +#![feature(const_ptr_read)] +#![feature(const_ptr_offset)] + +fn main() { + use std::ptr; + + const DATA: [u32; 1] = [42]; + + const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) }; + + const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; + const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; + const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; +} diff --git a/src/test/ui/const-ptr/out_of_bounds_read.stderr b/src/test/ui/const-ptr/out_of_bounds_read.stderr new file mode 100644 index 0000000000000..67175d5d1f5c3 --- /dev/null +++ b/src/test/ui/const-ptr/out_of_bounds_read.stderr @@ -0,0 +1,70 @@ +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | unsafe { copy_nonoverlapping(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL + | + ::: $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | --------------------------------------------- inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + ::: $DIR/out_of_bounds_read.rs:13:33 + | +LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; + | ----------------------- inside `_READ` at $DIR/out_of_bounds_read.rs:13:33 + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | unsafe { copy_nonoverlapping(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL + | + ::: $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | --------------------------------------------- inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | +LL | unsafe { read(self) } + | ---------- inside `ptr::const_ptr::::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + ::: $DIR/out_of_bounds_read.rs:14:39 + | +LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; + | ------------------- inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39 + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | unsafe { copy_nonoverlapping(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL + | + ::: $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | --------------------------------------------- inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + ::: $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + | +LL | unsafe { read(self) } + | ---------- inside `ptr::mut_ptr::::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + | + ::: $DIR/out_of_bounds_read.rs:15:37 + | +LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; + | --------------------------------- inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37 + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/copy-intrinsic.rs b/src/test/ui/consts/copy-intrinsic.rs new file mode 100644 index 0000000000000..48d128b10e802 --- /dev/null +++ b/src/test/ui/consts/copy-intrinsic.rs @@ -0,0 +1,51 @@ +#![stable(feature = "dummy", since = "1.0.0")] + +// ignore-tidy-linelength +#![feature(intrinsics, staged_api)] +#![feature(const_mut_refs, const_intrinsic_copy, const_ptr_offset)] +use std::mem; + +extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + fn copy(src: *const T, dst: *mut T, count: usize); +} + +const COPY_ZERO: () = unsafe { + // Since we are not copying anything, this should be allowed. + let src = (); + let mut dst = (); + copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0); +}; + +const COPY_OOB_1: () = unsafe { + let mut x = 0i32; + let dangle = (&mut x as *mut i32).wrapping_add(10); + // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs. + copy_nonoverlapping(0x100 as *const i32, dangle, 0); //~ evaluation of constant value failed [E0080] +}; +const COPY_OOB_2: () = unsafe { + let x = 0i32; + let dangle = (&x as *const i32).wrapping_add(10); + // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs. + copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); //~ evaluation of constant value failed [E0080] + //~| memory access failed: pointer must be in-bounds +}; + +const COPY_SIZE_OVERFLOW: () = unsafe { + let x = 0; + let mut y = 0; + copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); //~ evaluation of constant value failed [E0080] + //~| overflow computing total size of `copy` +}; +const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe { + let x = 0; + let mut y = 0; + copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); //~ evaluation of constant value failed [E0080] + //~| overflow computing total size of `copy_nonoverlapping` +}; + +fn main() { +} diff --git a/src/test/ui/consts/copy-intrinsic.stderr b/src/test/ui/consts/copy-intrinsic.stderr new file mode 100644 index 0000000000000..c1779743e8e00 --- /dev/null +++ b/src/test/ui/consts/copy-intrinsic.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/copy-intrinsic.rs:27:5 + | +LL | copy_nonoverlapping(0x100 as *const i32, dangle, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc4 which has size 4 + +error[E0080]: evaluation of constant value failed + --> $DIR/copy-intrinsic.rs:33:5 + | +LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc6 which has size 4 + +error[E0080]: evaluation of constant value failed + --> $DIR/copy-intrinsic.rs:40:5 + | +LL | copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` + +error[E0080]: evaluation of constant value failed + --> $DIR/copy-intrinsic.rs:46:5 + | +LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/thread-local-static.rs b/src/test/ui/thread-local-static.rs index dc542fe2db961..c7fee9e6b4c5a 100644 --- a/src/test/ui/thread-local-static.rs +++ b/src/test/ui/thread-local-static.rs @@ -11,7 +11,6 @@ const fn g(x: &mut [u32; 8]) { //~| ERROR mutable references are not allowed //~| ERROR use of mutable static is unsafe //~| constant functions cannot refer to statics - //~| ERROR calls in constant functions are limited to constant functions } fn main() {} diff --git a/src/test/ui/thread-local-static.stderr b/src/test/ui/thread-local-static.stderr index a213282eb85cd..08bf593a5a748 100644 --- a/src/test/ui/thread-local-static.stderr +++ b/src/test/ui/thread-local-static.stderr @@ -30,12 +30,6 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/thread-local-static.rs:9:5 - | -LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/thread-local-static.rs:9:23 | @@ -44,7 +38,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0013, E0015, E0133, E0658. +Some errors have detailed explanations: E0013, E0133, E0658. For more information about an error, try `rustc --explain E0013`.