about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-11-05 05:56:21 +0000
committerbors <bors@rust-lang.org>2023-11-05 05:56:21 +0000
commitda1e0d1d75bc029adfa30c596b526bc17436453e (patch)
tree024381f8c820e2f9cb8f0d9211bbe1f4561b5796
parentf64d028196e06ca523ac5de442dc4772cfa58b47 (diff)
parent5e5f3341e3749f18a6d6fbb2228a9d3b42c0b280 (diff)
downloadrust-da1e0d1d75bc029adfa30c596b526bc17436453e.tar.gz
rust-da1e0d1d75bc029adfa30c596b526bc17436453e.zip
Auto merge of #116218 - tgross35:const-maybe-uninit-zeroed, r=dtolnay
Stabilize `const_maybe_uninit_zeroed` and `const_mem_zeroed`

Make `MaybeUninit::zeroed` and `mem::zeroed` const stable. Newly stable API:

```rust
// core::mem
pub const unsafe fn zeroed<T>() ->;

impl<T> MaybeUninit<T> {
    pub const fn zeroed() -> MaybeUninit<T>;
}
```

This relies on features based around `const_mut_refs`. Per `@RalfJung,` this should be OK since we do not leak any `&mut` to the user.

For this to be possible, intrinsics `assert_zero_valid` and `assert_mem_uninitialized_valid` were made const stable.

Tracking issue: #91850
Zulip discussion: https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/topic/.60const_mut_refs.60.20dependents

r? libs-api
`@rustbot` label -T-libs +T-libs-api +A-const-eval
cc `@RalfJung`  `@oli-obk` `@rust-lang/wg-const-eval`
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/core/src/intrinsics.rs4
-rw-r--r--library/core/src/mem/maybe_uninit.rs17
-rw-r--r--library/core/src/mem/mod.rs3
-rw-r--r--library/core/tests/mem.rs21
-rw-r--r--tests/ui/consts/assert-type-intrinsics.rs1
-rw-r--r--tests/ui/consts/assert-type-intrinsics.stderr12
7 files changed, 42 insertions, 17 deletions
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 4f0a02da440..d33c4418e1b 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -115,7 +115,6 @@
 #![feature(const_eval_select)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_maybe_uninit_write)]
-#![feature(const_maybe_uninit_zeroed)]
 #![feature(const_pin)]
 #![feature(const_refs_to_cell)]
 #![feature(const_size_of_val)]
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 964aa3906f1..f855b2ad483 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1072,7 +1072,7 @@ extern "rust-intrinsic" {
     /// zero-initialization: This will statically either panic, or do nothing.
     ///
     /// This intrinsic does not have a stable counterpart.
-    #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
+    #[rustc_const_stable(feature = "const_assert_type2", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn assert_zero_valid<T>();
@@ -1080,7 +1080,7 @@ extern "rust-intrinsic" {
     /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing.
     ///
     /// This intrinsic does not have a stable counterpart.
-    #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
+    #[rustc_const_stable(feature = "const_assert_type2", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn assert_mem_uninitialized_valid<T>();
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 855bb1675c5..8a4070ebd96 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -374,6 +374,9 @@ impl<T> MaybeUninit<T> {
     /// assert_eq!(x, (0, false));
     /// ```
     ///
+    /// This can be used in const contexts, such as to indicate the end of static arrays for
+    /// plugin registration.
+    ///
     /// *Incorrect* usage of this function: calling `x.zeroed().assume_init()`
     /// when `0` is not a valid bit-pattern for the type:
     ///
@@ -387,17 +390,19 @@ impl<T> MaybeUninit<T> {
     /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant.
     /// // This is undefined behavior. ⚠️
     /// ```
-    #[stable(feature = "maybe_uninit", since = "1.36.0")]
-    #[rustc_const_unstable(feature = "const_maybe_uninit_zeroed", issue = "91850")]
-    #[must_use]
     #[inline]
+    #[must_use]
     #[rustc_diagnostic_item = "maybe_uninit_zeroed"]
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
+    // These are OK to allow since we do not leak &mut to user-visible API
+    #[rustc_allow_const_fn_unstable(const_mut_refs)]
+    #[rustc_allow_const_fn_unstable(const_ptr_write)]
+    #[rustc_allow_const_fn_unstable(const_maybe_uninit_as_mut_ptr)]
+    #[rustc_const_stable(feature = "const_maybe_uninit_zeroed", since = "CURRENT_RUSTC_VERSION")]
     pub const fn zeroed() -> MaybeUninit<T> {
         let mut u = MaybeUninit::<T>::uninit();
         // SAFETY: `u.as_mut_ptr()` points to allocated memory.
-        unsafe {
-            u.as_mut_ptr().write_bytes(0u8, 1);
-        }
+        unsafe { u.as_mut_ptr().write_bytes(0u8, 1) };
         u
     }
 
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 9159ecb740d..caf16827ad0 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -647,7 +647,8 @@ pub const fn needs_drop<T: ?Sized>() -> bool {
 #[allow(deprecated)]
 #[rustc_diagnostic_item = "mem_zeroed"]
 #[track_caller]
-pub unsafe fn zeroed<T>() -> T {
+#[rustc_const_stable(feature = "const_mem_zeroed", since = "CURRENT_RUSTC_VERSION")]
+pub const unsafe fn zeroed<T>() -> T {
     // SAFETY: the caller must guarantee that an all-zero value is valid for `T`.
     unsafe {
         intrinsics::assert_zero_valid::<T>();
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
index 5c2e18745ea..20498b16cb2 100644
--- a/library/core/tests/mem.rs
+++ b/library/core/tests/mem.rs
@@ -565,3 +565,24 @@ fn offset_of_addr() {
     assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.0), ptr::addr_of!(base.z.0).addr());
     assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.1), ptr::addr_of!(base.z.1).addr());
 }
+
+#[test]
+fn const_maybe_uninit_zeroed() {
+    // Sanity check for `MaybeUninit::zeroed` in a realistic const situation (plugin array term)
+    #[repr(C)]
+    struct Foo {
+        a: Option<&'static str>,
+        b: Bar,
+        c: f32,
+        d: *const u8,
+    }
+    #[repr(C)]
+    struct Bar(usize);
+    struct FooPtr(*const Foo);
+    unsafe impl Sync for FooPtr {}
+
+    static UNINIT: FooPtr = FooPtr([unsafe { MaybeUninit::zeroed().assume_init() }].as_ptr());
+    const SIZE: usize = size_of::<Foo>();
+
+    assert_eq!(unsafe { (*UNINIT.0.cast::<[[u8; SIZE]; 1]>())[0] }, [0u8; SIZE]);
+}
diff --git a/tests/ui/consts/assert-type-intrinsics.rs b/tests/ui/consts/assert-type-intrinsics.rs
index b4fd423becd..32b5f5c92c5 100644
--- a/tests/ui/consts/assert-type-intrinsics.rs
+++ b/tests/ui/consts/assert-type-intrinsics.rs
@@ -1,5 +1,4 @@
 #![feature(never_type)]
-#![feature(const_assert_type2)]
 #![feature(core_intrinsics)]
 
 use std::intrinsics;
diff --git a/tests/ui/consts/assert-type-intrinsics.stderr b/tests/ui/consts/assert-type-intrinsics.stderr
index 3c03b03deee..66c4f0f9cd6 100644
--- a/tests/ui/consts/assert-type-intrinsics.stderr
+++ b/tests/ui/consts/assert-type-intrinsics.stderr
@@ -1,20 +1,20 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/assert-type-intrinsics.rs:12:9
+  --> $DIR/assert-type-intrinsics.rs:11:9
    |
 LL |         MaybeUninit::<!>::uninit().assume_init();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to instantiate uninhabited type `!`', $DIR/assert-type-intrinsics.rs:12:36
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to instantiate uninhabited type `!`', $DIR/assert-type-intrinsics.rs:11:36
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/assert-type-intrinsics.rs:16:9
+  --> $DIR/assert-type-intrinsics.rs:15:9
    |
 LL |         intrinsics::assert_mem_uninitialized_valid::<&'static i32>();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to leave type `&i32` uninitialized, which is invalid', $DIR/assert-type-intrinsics.rs:16:9
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to leave type `&i32` uninitialized, which is invalid', $DIR/assert-type-intrinsics.rs:15:9
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/assert-type-intrinsics.rs:20:9
+  --> $DIR/assert-type-intrinsics.rs:19:9
    |
 LL |         intrinsics::assert_zero_valid::<&'static i32>();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to zero-initialize type `&i32`, which is invalid', $DIR/assert-type-intrinsics.rs:20:9
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to zero-initialize type `&i32`, which is invalid', $DIR/assert-type-intrinsics.rs:19:9
 
 error: aborting due to 3 previous errors