Skip to content

Commit 72c66ad

Browse files
committed
Auto merge of rust-lang#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: rust-lang#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`
2 parents b182b30 + b0ae6de commit 72c66ad

File tree

5 files changed

+36
-10
lines changed

5 files changed

+36
-10
lines changed

alloc/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@
115115
#![feature(const_eval_select)]
116116
#![feature(const_maybe_uninit_as_mut_ptr)]
117117
#![feature(const_maybe_uninit_write)]
118-
#![feature(const_maybe_uninit_zeroed)]
119118
#![feature(const_pin)]
120119
#![feature(const_refs_to_cell)]
121120
#![feature(const_size_of_val)]

core/src/intrinsics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,15 +1072,15 @@ extern "rust-intrinsic" {
10721072
/// zero-initialization: This will statically either panic, or do nothing.
10731073
///
10741074
/// This intrinsic does not have a stable counterpart.
1075-
#[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
1075+
#[rustc_const_stable(feature = "const_assert_type2", since = "CURRENT_RUSTC_VERSION")]
10761076
#[rustc_safe_intrinsic]
10771077
#[rustc_nounwind]
10781078
pub fn assert_zero_valid<T>();
10791079

10801080
/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing.
10811081
///
10821082
/// This intrinsic does not have a stable counterpart.
1083-
#[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
1083+
#[rustc_const_stable(feature = "const_assert_type2", since = "CURRENT_RUSTC_VERSION")]
10841084
#[rustc_safe_intrinsic]
10851085
#[rustc_nounwind]
10861086
pub fn assert_mem_uninitialized_valid<T>();

core/src/mem/maybe_uninit.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,9 @@ impl<T> MaybeUninit<T> {
374374
/// assert_eq!(x, (0, false));
375375
/// ```
376376
///
377+
/// This can be used in const contexts, such as to indicate the end of static arrays for
378+
/// plugin registration.
379+
///
377380
/// *Incorrect* usage of this function: calling `x.zeroed().assume_init()`
378381
/// when `0` is not a valid bit-pattern for the type:
379382
///
@@ -387,17 +390,19 @@ impl<T> MaybeUninit<T> {
387390
/// // Inside a pair, we create a `NotZero` that does not have a valid discriminant.
388391
/// // This is undefined behavior. ⚠️
389392
/// ```
390-
#[stable(feature = "maybe_uninit", since = "1.36.0")]
391-
#[rustc_const_unstable(feature = "const_maybe_uninit_zeroed", issue = "91850")]
392-
#[must_use]
393393
#[inline]
394+
#[must_use]
394395
#[rustc_diagnostic_item = "maybe_uninit_zeroed"]
396+
#[stable(feature = "maybe_uninit", since = "1.36.0")]
397+
// These are OK to allow since we do not leak &mut to user-visible API
398+
#[rustc_allow_const_fn_unstable(const_mut_refs)]
399+
#[rustc_allow_const_fn_unstable(const_ptr_write)]
400+
#[rustc_allow_const_fn_unstable(const_maybe_uninit_as_mut_ptr)]
401+
#[rustc_const_stable(feature = "const_maybe_uninit_zeroed", since = "CURRENT_RUSTC_VERSION")]
395402
pub const fn zeroed() -> MaybeUninit<T> {
396403
let mut u = MaybeUninit::<T>::uninit();
397404
// SAFETY: `u.as_mut_ptr()` points to allocated memory.
398-
unsafe {
399-
u.as_mut_ptr().write_bytes(0u8, 1);
400-
}
405+
unsafe { u.as_mut_ptr().write_bytes(0u8, 1) };
401406
u
402407
}
403408

core/src/mem/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,8 @@ pub const fn needs_drop<T: ?Sized>() -> bool {
647647
#[allow(deprecated)]
648648
#[rustc_diagnostic_item = "mem_zeroed"]
649649
#[track_caller]
650-
pub unsafe fn zeroed<T>() -> T {
650+
#[rustc_const_stable(feature = "const_mem_zeroed", since = "CURRENT_RUSTC_VERSION")]
651+
pub const unsafe fn zeroed<T>() -> T {
651652
// SAFETY: the caller must guarantee that an all-zero value is valid for `T`.
652653
unsafe {
653654
intrinsics::assert_zero_valid::<T>();

core/tests/mem.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,3 +565,24 @@ fn offset_of_addr() {
565565
assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.0), ptr::addr_of!(base.z.0).addr());
566566
assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.1), ptr::addr_of!(base.z.1).addr());
567567
}
568+
569+
#[test]
570+
fn const_maybe_uninit_zeroed() {
571+
// Sanity check for `MaybeUninit::zeroed` in a realistic const situation (plugin array term)
572+
#[repr(C)]
573+
struct Foo {
574+
a: Option<&'static str>,
575+
b: Bar,
576+
c: f32,
577+
d: *const u8,
578+
}
579+
#[repr(C)]
580+
struct Bar(usize);
581+
struct FooPtr(*const Foo);
582+
unsafe impl Sync for FooPtr {}
583+
584+
static UNINIT: FooPtr = FooPtr([unsafe { MaybeUninit::zeroed().assume_init() }].as_ptr());
585+
const SIZE: usize = size_of::<Foo>();
586+
587+
assert_eq!(unsafe { (*UNINIT.0.cast::<[[u8; SIZE]; 1]>())[0] }, [0u8; SIZE]);
588+
}

0 commit comments

Comments
 (0)