about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-06-27 13:19:48 +0000
committerbors <bors@rust-lang.org>2021-06-27 13:19:48 +0000
commit49ba9361d87f5d58d54fdd164ef2128cd50ed4b4 (patch)
tree9efc0b34c080247f2c656b7e4e4e04a0bc31befd
parent543ab9964065dc2b4e47d7bff5e83c84519f265e (diff)
parent4aa1267cbb9d2428e9da6fa05838206c965a96d4 (diff)
downloadrust-49ba9361d87f5d58d54fdd164ef2128cd50ed4b4.tar.gz
rust-49ba9361d87f5d58d54fdd164ef2128cd50ed4b4.zip
Auto merge of #86295 - usbalbin:revert_revert_of_constness, r=RalfJung
Revert revert of constness in #86003

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

Once the checks pass, this should solve #86236
-rw-r--r--library/core/src/mem/mod.rs6
-rw-r--r--library/core/src/ptr/mod.rs12
-rw-r--r--library/core/src/ptr/mut_ptr.rs5
-rw-r--r--library/core/tests/const_ptr.rs50
-rw-r--r--src/test/ui/const-ptr/out_of_bounds_read.rs16
-rw-r--r--src/test/ui/const-ptr/out_of_bounds_read.stderr70
-rw-r--r--src/test/ui/consts/copy-intrinsic.rs51
-rw-r--r--src/test/ui/consts/copy-intrinsic.stderr27
-rw-r--r--src/test/ui/thread-local-static.rs1
-rw-r--r--src/test/ui/thread-local-static.stderr10
10 files changed, 231 insertions, 17 deletions
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index c6750c52d16..5bf47c3951d 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -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 {
@@ -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.
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 6a6cee0911f..4b81c39ea1d 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<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
@@ -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
@@ -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);
     }
 
@@ -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
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index a6424041542..93ee74719ff 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -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,
     {
@@ -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
diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs
index 4acd059ab03..152fed803ec 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 00000000000..c45198cc39b
--- /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 00000000000..67175d5d1f5
--- /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::<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`.
diff --git a/src/test/ui/consts/copy-intrinsic.rs b/src/test/ui/consts/copy-intrinsic.rs
new file mode 100644
index 00000000000..48d128b10e8
--- /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<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() {
+}
diff --git a/src/test/ui/consts/copy-intrinsic.stderr b/src/test/ui/consts/copy-intrinsic.stderr
new file mode 100644
index 00000000000..c1779743e8e
--- /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::<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`.
diff --git a/src/test/ui/thread-local-static.rs b/src/test/ui/thread-local-static.rs
index dc542fe2db9..c7fee9e6b4c 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 a213282eb85..08bf593a5a7 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 <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
    |
@@ -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`.