Skip to content

Commit

Permalink
Auto merge of rust-lang#86295 - usbalbin:revert_revert_of_constness, …
Browse files Browse the repository at this point in the history
…r=RalfJung

Revert revert of constness in rust-lang#86003

Re-constify `mem::swap`, `mem::replace`, `ptr::write` which were marked as not `const` in rust-lang#86003

Once the checks pass, this should solve rust-lang#86236
  • Loading branch information
bors committed Jun 27, 2021
2 parents 543ab99 + 4aa1267 commit 49ba936
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 17 deletions.
6 changes: 4 additions & 2 deletions library/core/src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,8 @@ pub unsafe fn uninitialized<T>() -> T {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn swap<T>(x: &mut T, y: &mut T) {
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
pub const fn swap<T>(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 {
Expand Down Expand Up @@ -812,7 +813,8 @@ pub fn take<T: Default>(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<T>(dest: &mut T, src: T) -> T {
#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
pub const fn replace<T>(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.
Expand Down
12 changes: 8 additions & 4 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,8 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
}

#[inline]
pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
pub(crate) const unsafe fn swap_nonoverlapping_one<T>(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
Expand Down Expand Up @@ -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<T>(dst: *mut T, mut src: T) -> T {
#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
pub const unsafe fn replace<T>(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
Expand Down Expand Up @@ -869,10 +871,12 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn write<T>(dst: *mut T, src: T) {
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
pub const unsafe fn write<T>(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<T>(src: *const T, dst: *mut T, count: usize);
}

Expand Down Expand Up @@ -964,7 +968,7 @@ pub unsafe fn write<T>(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<T>(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
Expand Down
5 changes: 3 additions & 2 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,8 +1002,9 @@ impl<T: ?Sized> *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,
{
Expand Down Expand Up @@ -1056,7 +1057,7 @@ impl<T: ?Sized> *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
Expand Down
50 changes: 50 additions & 0 deletions library/core/tests/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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])]);
}
16 changes: 16 additions & 0 deletions src/test/ui/const-ptr/out_of_bounds_read.rs
Original file line number Diff line number Diff line change
@@ -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() };
}
70 changes: 70 additions & 0 deletions src/test/ui/const-ptr/out_of_bounds_read.stderr
Original file line number Diff line number Diff line change
@@ -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::<u32>` 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::<u32>` 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::<u32>` 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::<u32>` 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::<impl *const u32>::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::<u32>` 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::<u32>` 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::<impl *mut u32>::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`.
51 changes: 51 additions & 0 deletions src/test/ui/consts/copy-intrinsic.rs
Original file line number Diff line number Diff line change
@@ -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<T>(src: *const T, dst: *mut T, count: usize);

#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
fn copy<T>(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::<usize>() * 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::<usize>() * 8 - 1)); //~ evaluation of constant value failed [E0080]
//~| overflow computing total size of `copy_nonoverlapping`
};

fn main() {
}
27 changes: 27 additions & 0 deletions src/test/ui/consts/copy-intrinsic.stderr
Original file line number Diff line number Diff line change
@@ -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::<usize>() * 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::<usize>() * 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`.
1 change: 0 additions & 1 deletion src/test/ui/thread-local-static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
10 changes: 2 additions & 8 deletions src/test/ui/thread-local-static.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2)
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/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
|
Expand All @@ -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`.

0 comments on commit 49ba936

Please sign in to comment.