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`
This commit is contained in:
commit
da1e0d1d75
@ -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)]
|
||||
|
@ -1072,7 +1072,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
||||
/// 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 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
||||
/// 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>();
|
||||
|
@ -374,6 +374,9 @@ pub const fn uninit() -> 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 @@ pub const fn uninit() -> 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
|
||||
}
|
||||
|
||||
|
@ -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>();
|
||||
|
@ -565,3 +565,24 @@ struct Foo {
|
||||
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]);
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(const_assert_type2)]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
use std::intrinsics;
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user