Skip to content

Commit 49ba936

Browse files
committed
Auto merge of rust-lang#86295 - usbalbin:revert_revert_of_constness, 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
2 parents 543ab99 + 4aa1267 commit 49ba936

File tree

10 files changed

+231
-17
lines changed

10 files changed

+231
-17
lines changed

library/core/src/mem/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,8 @@ pub unsafe fn uninitialized<T>() -> T {
682682
/// ```
683683
#[inline]
684684
#[stable(feature = "rust1", since = "1.0.0")]
685-
pub fn swap<T>(x: &mut T, y: &mut T) {
685+
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
686+
pub const fn swap<T>(x: &mut T, y: &mut T) {
686687
// SAFETY: the raw pointers have been created from safe mutable references satisfying all the
687688
// constraints on `ptr::swap_nonoverlapping_one`
688689
unsafe {
@@ -812,7 +813,8 @@ pub fn take<T: Default>(dest: &mut T) -> T {
812813
#[inline]
813814
#[stable(feature = "rust1", since = "1.0.0")]
814815
#[must_use = "if you don't need the old value, you can just assign the new value directly"]
815-
pub fn replace<T>(dest: &mut T, src: T) -> T {
816+
#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
817+
pub const fn replace<T>(dest: &mut T, src: T) -> T {
816818
// SAFETY: We read from `dest` but directly write `src` into it afterwards,
817819
// such that the old value is not duplicated. Nothing is dropped and
818820
// nothing here can panic.

library/core/src/ptr/mod.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,8 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
430430
}
431431

432432
#[inline]
433-
pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
433+
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
434+
pub(crate) const unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
434435
// NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
435436
// reinterpretation of values as (chunkable) byte arrays, and the loop in the
436437
// 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) {
563564
/// ```
564565
#[inline]
565566
#[stable(feature = "rust1", since = "1.0.0")]
566-
pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
567+
#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
568+
pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
567569
// SAFETY: the caller must guarantee that `dst` is valid to be
568570
// cast to a mutable reference (valid for writes, aligned, initialized),
569571
// and cannot overlap `src` since `dst` must point to a distinct
@@ -869,10 +871,12 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
869871
/// ```
870872
#[inline]
871873
#[stable(feature = "rust1", since = "1.0.0")]
872-
pub unsafe fn write<T>(dst: *mut T, src: T) {
874+
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
875+
pub const unsafe fn write<T>(dst: *mut T, src: T) {
873876
// We are calling the intrinsics directly to avoid function calls in the generated code
874877
// as `intrinsics::copy_nonoverlapping` is a wrapper function.
875878
extern "rust-intrinsic" {
879+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
876880
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
877881
}
878882

@@ -964,7 +968,7 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
964968
/// ```
965969
#[inline]
966970
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
967-
#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")]
971+
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
968972
pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
969973
// SAFETY: the caller must guarantee that `dst` is valid for writes.
970974
// `dst` cannot overlap `src` because the caller has mutable access

library/core/src/ptr/mut_ptr.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1002,8 +1002,9 @@ impl<T: ?Sized> *mut T {
10021002
///
10031003
/// [`ptr::write`]: crate::ptr::write()
10041004
#[stable(feature = "pointer_methods", since = "1.26.0")]
1005+
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
10051006
#[inline(always)]
1006-
pub unsafe fn write(self, val: T)
1007+
pub const unsafe fn write(self, val: T)
10071008
where
10081009
T: Sized,
10091010
{
@@ -1056,7 +1057,7 @@ impl<T: ?Sized> *mut T {
10561057
///
10571058
/// [`ptr::write_unaligned`]: crate::ptr::write_unaligned()
10581059
#[stable(feature = "pointer_methods", since = "1.26.0")]
1059-
#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")]
1060+
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
10601061
#[inline(always)]
10611062
pub const unsafe fn write_unaligned(self, val: T)
10621063
where

library/core/tests/const_ptr.rs

+50
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,53 @@ fn mut_ptr_read() {
4949
const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
5050
assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
5151
}
52+
53+
#[test]
54+
fn write() {
55+
use core::ptr;
56+
57+
const fn write_aligned() -> i32 {
58+
let mut res = 0;
59+
unsafe {
60+
ptr::write(&mut res as *mut _, 42);
61+
}
62+
res
63+
}
64+
const ALIGNED: i32 = write_aligned();
65+
assert_eq!(ALIGNED, 42);
66+
67+
const fn write_unaligned() -> [u16; 2] {
68+
let mut two_aligned = [0u16; 2];
69+
unsafe {
70+
let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
71+
ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45]));
72+
}
73+
two_aligned
74+
}
75+
const UNALIGNED: [u16; 2] = write_unaligned();
76+
assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]);
77+
}
78+
79+
#[test]
80+
fn mut_ptr_write() {
81+
const fn aligned() -> i32 {
82+
let mut res = 0;
83+
unsafe {
84+
(&mut res as *mut i32).write(42);
85+
}
86+
res
87+
}
88+
const ALIGNED: i32 = aligned();
89+
assert_eq!(ALIGNED, 42);
90+
91+
const fn write_unaligned() -> [u16; 2] {
92+
let mut two_aligned = [0u16; 2];
93+
unsafe {
94+
let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
95+
unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45]));
96+
}
97+
two_aligned
98+
}
99+
const UNALIGNED: [u16; 2] = write_unaligned();
100+
assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]);
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// error-pattern: evaluation of constant value failed
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,70 @@
1+
error[E0080]: evaluation of constant value failed
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+
|
10+
::: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
11+
|
12+
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
13+
| --------------------------------------------- inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
14+
|
15+
::: $DIR/out_of_bounds_read.rs:13:33
16+
|
17+
LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
18+
| ----------------------- inside `_READ` at $DIR/out_of_bounds_read.rs:13:33
19+
20+
error[E0080]: evaluation of constant value failed
21+
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
22+
|
23+
LL | unsafe { copy_nonoverlapping(src, dst, count) }
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
25+
| |
26+
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
27+
| inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
28+
|
29+
::: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
30+
|
31+
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
32+
| --------------------------------------------- inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
33+
|
34+
::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
35+
|
36+
LL | unsafe { read(self) }
37+
| ---------- inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
38+
|
39+
::: $DIR/out_of_bounds_read.rs:14:39
40+
|
41+
LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
42+
| ------------------- inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39
43+
44+
error[E0080]: evaluation of constant value failed
45+
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
46+
|
47+
LL | unsafe { copy_nonoverlapping(src, dst, count) }
48+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49+
| |
50+
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
51+
| inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
52+
|
53+
::: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
54+
|
55+
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
56+
| --------------------------------------------- inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
57+
|
58+
::: $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
59+
|
60+
LL | unsafe { read(self) }
61+
| ---------- inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
62+
|
63+
::: $DIR/out_of_bounds_read.rs:15:37
64+
|
65+
LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
66+
| --------------------------------- inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37
67+
68+
error: aborting due to 3 previous errors
69+
70+
For more information about this error, try `rustc --explain E0080`.

src/test/ui/consts/copy-intrinsic.rs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#![stable(feature = "dummy", since = "1.0.0")]
2+
3+
// ignore-tidy-linelength
4+
#![feature(intrinsics, staged_api)]
5+
#![feature(const_mut_refs, const_intrinsic_copy, const_ptr_offset)]
6+
use std::mem;
7+
8+
extern "rust-intrinsic" {
9+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
10+
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
11+
12+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
13+
fn copy<T>(src: *const T, dst: *mut T, count: usize);
14+
}
15+
16+
const COPY_ZERO: () = unsafe {
17+
// Since we are not copying anything, this should be allowed.
18+
let src = ();
19+
let mut dst = ();
20+
copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
21+
};
22+
23+
const COPY_OOB_1: () = unsafe {
24+
let mut x = 0i32;
25+
let dangle = (&mut x as *mut i32).wrapping_add(10);
26+
// Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
27+
copy_nonoverlapping(0x100 as *const i32, dangle, 0); //~ evaluation of constant value failed [E0080]
28+
};
29+
const COPY_OOB_2: () = unsafe {
30+
let x = 0i32;
31+
let dangle = (&x as *const i32).wrapping_add(10);
32+
// Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
33+
copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); //~ evaluation of constant value failed [E0080]
34+
//~| memory access failed: pointer must be in-bounds
35+
};
36+
37+
const COPY_SIZE_OVERFLOW: () = unsafe {
38+
let x = 0;
39+
let mut y = 0;
40+
copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ evaluation of constant value failed [E0080]
41+
//~| overflow computing total size of `copy`
42+
};
43+
const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe {
44+
let x = 0;
45+
let mut y = 0;
46+
copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ evaluation of constant value failed [E0080]
47+
//~| overflow computing total size of `copy_nonoverlapping`
48+
};
49+
50+
fn main() {
51+
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0080]: evaluation of constant value failed
2+
--> $DIR/copy-intrinsic.rs:27:5
3+
|
4+
LL | copy_nonoverlapping(0x100 as *const i32, dangle, 0);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc4 which has size 4
6+
7+
error[E0080]: evaluation of constant value failed
8+
--> $DIR/copy-intrinsic.rs:33:5
9+
|
10+
LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 0);
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc6 which has size 4
12+
13+
error[E0080]: evaluation of constant value failed
14+
--> $DIR/copy-intrinsic.rs:40:5
15+
|
16+
LL | copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
18+
19+
error[E0080]: evaluation of constant value failed
20+
--> $DIR/copy-intrinsic.rs:46:5
21+
|
22+
LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`
24+
25+
error: aborting due to 4 previous errors
26+
27+
For more information about this error, try `rustc --explain E0080`.

src/test/ui/thread-local-static.rs

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ const fn g(x: &mut [u32; 8]) {
1111
//~| ERROR mutable references are not allowed
1212
//~| ERROR use of mutable static is unsafe
1313
//~| constant functions cannot refer to statics
14-
//~| ERROR calls in constant functions are limited to constant functions
1514
}
1615

1716
fn main() {}

src/test/ui/thread-local-static.stderr

+2-8
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2)
3030
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
3131
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
3232

33-
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
34-
--> $DIR/thread-local-static.rs:9:5
35-
|
36-
LL | std::mem::swap(x, &mut STATIC_VAR_2)
37-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38-
3933
error[E0133]: use of mutable static is unsafe and requires unsafe function or block
4034
--> $DIR/thread-local-static.rs:9:23
4135
|
@@ -44,7 +38,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2)
4438
|
4539
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
4640

47-
error: aborting due to 6 previous errors
41+
error: aborting due to 5 previous errors
4842

49-
Some errors have detailed explanations: E0013, E0015, E0133, E0658.
43+
Some errors have detailed explanations: E0013, E0133, E0658.
5044
For more information about an error, try `rustc --explain E0013`.

0 commit comments

Comments
 (0)