Skip to content

Commit 39b841d

Browse files
committed
Auto merge of #79621 - usbalbin:constier_maybe_uninit, r=RalfJung
Constier maybe uninit I was playing around trying to make `[T; N]::zip()` in #79451 be `const fn`. One of the things I bumped into was `MaybeUninit::assume_init`. Is there any reason for the intrinsic `assert_inhabited<T>()` and therefore `MaybeUninit::assume_init` not being `const`? --- I have as best as I could tried to follow the instruction in [library/core/src/intrinsics.rs](https://github.com/rust-lang/rust/blob/master/library/core/src/intrinsics.rs#L11). I have no idea what I am doing but it seems to compile after some slight changes after the copy paste. Is this anywhere near how this should be done? Also any ideas for name of the feature gate? I guess `const_maybe_assume_init` is quite misleading since I have added some more methods. Should I add test? If so what should be tested?
2 parents e413d89 + 0775271 commit 39b841d

File tree

12 files changed

+87
-14
lines changed

12 files changed

+87
-14
lines changed

compiler/rustc_mir/src/const_eval/error.rs

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub enum ConstEvalErrKind {
2020
ModifiedGlobal,
2121
AssertFailure(AssertKind<ConstInt>),
2222
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
23+
Abort(String),
2324
}
2425

2526
// The errors become `MachineStop` with plain strings when being raised.
@@ -46,6 +47,7 @@ impl fmt::Display for ConstEvalErrKind {
4647
Panic { msg, line, col, file } => {
4748
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col)
4849
}
50+
Abort(ref msg) => write!(f, "{}", msg),
4951
}
5052
}
5153
}

compiler/rustc_mir/src/const_eval/machine.rs

+4
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
384384
Err(ConstEvalErrKind::AssertFailure(err).into())
385385
}
386386

387+
fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> {
388+
Err(ConstEvalErrKind::Abort(msg).into())
389+
}
390+
387391
fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> {
388392
Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into())
389393
}

compiler/rustc_mir/src/interpret/intrinsics.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
126126
None => match intrinsic_name {
127127
sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
128128
sym::unreachable => throw_ub!(Unreachable),
129-
sym::abort => M::abort(self)?,
129+
sym::abort => M::abort(self, "the program aborted execution".to_owned())?,
130130
// Unsupported diverging intrinsic.
131131
_ => return Ok(false),
132132
},
@@ -407,6 +407,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
407407
sym::transmute => {
408408
self.copy_op_transmute(args[0], dest)?;
409409
}
410+
sym::assert_inhabited => {
411+
let ty = instance.substs.type_at(0);
412+
let layout = self.layout_of(ty)?;
413+
414+
if layout.abi.is_uninhabited() {
415+
// The run-time intrinsic panics just to get a good backtrace; here we abort
416+
// since there is no problem showing a backtrace even for aborts.
417+
M::abort(self, format!("attempted to instantiate uninhabited type `{}`", ty))?;
418+
}
419+
}
410420
sym::simd_insert => {
411421
let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
412422
let elem = args[2];

compiler/rustc_mir/src/interpret/machine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
176176
) -> InterpResult<'tcx>;
177177

178178
/// Called to evaluate `Abort` MIR terminator.
179-
fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> {
179+
fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> {
180180
throw_unsup_format!("aborting execution is not supported")
181181
}
182182

compiler/rustc_mir/src/interpret/terminator.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
110110
}
111111

112112
Abort => {
113-
M::abort(self)?;
113+
M::abort(self, "the program aborted execution".to_owned())?;
114114
}
115115

116116
// When we encounter Resume, we've finished unwinding

library/core/src/intrinsics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,7 @@ extern "rust-intrinsic" {
815815
/// This will statically either panic, or do nothing.
816816
///
817817
/// This intrinsic does not have a stable counterpart.
818+
#[rustc_const_unstable(feature = "const_assert_type", issue = "none")]
818819
pub fn assert_inhabited<T>();
819820

820821
/// A guard for unsafe functions that cannot ever be executed if `T` does not permit

library/core/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
#![feature(cfg_target_has_atomic)]
7171
#![cfg_attr(not(bootstrap), feature(const_heap))]
7272
#![feature(const_alloc_layout)]
73+
#![feature(const_assert_type)]
7374
#![feature(const_discriminant)]
7475
#![feature(const_cell_into_inner)]
7576
#![feature(const_checked_int_methods)]
@@ -93,6 +94,7 @@
9394
#![feature(const_ptr_offset)]
9495
#![feature(const_ptr_offset_from)]
9596
#![feature(const_raw_ptr_comparison)]
97+
#![feature(const_raw_ptr_deref)]
9698
#![feature(const_slice_from_raw_parts)]
9799
#![feature(const_slice_ptr_len)]
98100
#![feature(const_size_of_val)]
@@ -101,6 +103,8 @@
101103
#![feature(const_type_name)]
102104
#![feature(const_likely)]
103105
#![feature(const_unreachable_unchecked)]
106+
#![feature(const_maybe_uninit_assume_init)]
107+
#![feature(const_maybe_uninit_as_ptr)]
104108
#![feature(custom_inner_attributes)]
105109
#![feature(decl_macro)]
106110
#![feature(doc_cfg)]

library/core/src/mem/maybe_uninit.rs

+20-11
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,9 @@ impl<T> MaybeUninit<T> {
314314
/// let data = read(&mut buf);
315315
/// ```
316316
#[unstable(feature = "maybe_uninit_uninit_array", issue = "none")]
317+
#[rustc_const_unstable(feature = "maybe_uninit_uninit_array", issue = "none")]
317318
#[inline(always)]
318-
pub fn uninit_array<const LEN: usize>() -> [Self; LEN] {
319+
pub const fn uninit_array<const LEN: usize>() -> [Self; LEN] {
319320
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
320321
unsafe { MaybeUninit::<[MaybeUninit<T>; LEN]>::uninit().assume_init() }
321322
}
@@ -372,8 +373,9 @@ impl<T> MaybeUninit<T> {
372373
/// skip running the destructor. For your convenience, this also returns a mutable
373374
/// reference to the (now safely initialized) contents of `self`.
374375
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
376+
#[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
375377
#[inline(always)]
376-
pub fn write(&mut self, val: T) -> &mut T {
378+
pub const fn write(&mut self, val: T) -> &mut T {
377379
*self = MaybeUninit::new(val);
378380
// SAFETY: We just initialized this value.
379381
unsafe { self.assume_init_mut() }
@@ -503,9 +505,10 @@ impl<T> MaybeUninit<T> {
503505
/// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️
504506
/// ```
505507
#[stable(feature = "maybe_uninit", since = "1.36.0")]
508+
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
506509
#[inline(always)]
507510
#[rustc_diagnostic_item = "assume_init"]
508-
pub unsafe fn assume_init(self) -> T {
511+
pub const unsafe fn assume_init(self) -> T {
509512
// SAFETY: the caller must guarantee that `self` is initialized.
510513
// This also means that `self` must be a `value` variant.
511514
unsafe {
@@ -666,13 +669,14 @@ impl<T> MaybeUninit<T> {
666669
/// }
667670
/// ```
668671
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
672+
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
669673
#[inline(always)]
670-
pub unsafe fn assume_init_ref(&self) -> &T {
674+
pub const unsafe fn assume_init_ref(&self) -> &T {
671675
// SAFETY: the caller must guarantee that `self` is initialized.
672676
// This also means that `self` must be a `value` variant.
673677
unsafe {
674678
intrinsics::assert_inhabited::<T>();
675-
&*self.value
679+
&*self.as_ptr()
676680
}
677681
}
678682

@@ -788,13 +792,14 @@ impl<T> MaybeUninit<T> {
788792
// to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make
789793
// a final decision about the rules before stabilization.
790794
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
795+
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
791796
#[inline(always)]
792-
pub unsafe fn assume_init_mut(&mut self) -> &mut T {
797+
pub const unsafe fn assume_init_mut(&mut self) -> &mut T {
793798
// SAFETY: the caller must guarantee that `self` is initialized.
794799
// This also means that `self` must be a `value` variant.
795800
unsafe {
796801
intrinsics::assert_inhabited::<T>();
797-
&mut *self.value
802+
&mut *self.as_mut_ptr()
798803
}
799804
}
800805

@@ -810,8 +815,9 @@ impl<T> MaybeUninit<T> {
810815
///
811816
/// [`assume_init_ref`]: MaybeUninit::assume_init_ref
812817
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
818+
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
813819
#[inline(always)]
814-
pub unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] {
820+
pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] {
815821
// SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that
816822
// `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`.
817823
// The pointer obtained is valid since it refers to memory owned by `slice` which is a
@@ -831,24 +837,27 @@ impl<T> MaybeUninit<T> {
831837
///
832838
/// [`assume_init_mut`]: MaybeUninit::assume_init_mut
833839
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
840+
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
834841
#[inline(always)]
835-
pub unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] {
842+
pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] {
836843
// SAFETY: similar to safety notes for `slice_get_ref`, but we have a
837844
// mutable reference which is also guaranteed to be valid for writes.
838845
unsafe { &mut *(slice as *mut [Self] as *mut [T]) }
839846
}
840847

841848
/// Gets a pointer to the first element of the array.
842849
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
850+
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
843851
#[inline(always)]
844-
pub fn slice_as_ptr(this: &[MaybeUninit<T>]) -> *const T {
852+
pub const fn slice_as_ptr(this: &[MaybeUninit<T>]) -> *const T {
845853
this.as_ptr() as *const T
846854
}
847855

848856
/// Gets a mutable pointer to the first element of the array.
849857
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
858+
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
850859
#[inline(always)]
851-
pub fn slice_as_mut_ptr(this: &mut [MaybeUninit<T>]) -> *mut T {
860+
pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit<T>]) -> *mut T {
852861
this.as_mut_ptr() as *mut T
853862
}
854863
}

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#![feature(cfg_target_has_atomic)]
1212
#![feature(const_assume)]
1313
#![feature(const_cell_into_inner)]
14+
#![feature(const_maybe_uninit_assume_init)]
1415
#![feature(core_intrinsics)]
1516
#![feature(core_private_bignum)]
1617
#![feature(core_private_diy_float)]

library/core/tests/mem.rs

+8
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,11 @@ fn test_discriminant_send_sync() {
129129
is_send_sync::<Discriminant<Regular>>();
130130
is_send_sync::<Discriminant<NotSendSync>>();
131131
}
132+
133+
#[test]
134+
#[cfg(not(bootstrap))]
135+
fn assume_init_good() {
136+
const TRUE: bool = unsafe { MaybeUninit::<bool>::new(true).assume_init() };
137+
138+
assert!(TRUE);
139+
}

src/test/ui/assume-type-intrinsics.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// error-pattern: any use of this value will cause an error
2+
3+
#![feature(never_type)]
4+
#![feature(const_maybe_uninit_assume_init)]
5+
6+
#[allow(invalid_value)]
7+
fn main() {
8+
use std::mem::MaybeUninit;
9+
10+
const _BAD: () = unsafe {
11+
MaybeUninit::<!>::uninit().assume_init();
12+
};
13+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error: any use of this value will cause an error
2+
--> $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL
3+
|
4+
LL | intrinsics::assert_inhabited::<T>();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| attempted to instantiate uninhabited type `!`
8+
| inside `MaybeUninit::<!>::assume_init` at $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL
9+
| inside `_BAD` at $DIR/assume-type-intrinsics.rs:11:9
10+
|
11+
::: $DIR/assume-type-intrinsics.rs:10:5
12+
|
13+
LL | / const _BAD: () = unsafe {
14+
LL | | MaybeUninit::<!>::uninit().assume_init();
15+
LL | | };
16+
| |______-
17+
|
18+
= note: `#[deny(const_err)]` on by default
19+
20+
error: aborting due to previous error
21+

0 commit comments

Comments
 (0)