Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_mir/src/const_eval/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub enum ConstEvalErrKind {
ModifiedGlobal,
AssertFailure(AssertKind<ConstInt>),
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
Abort(String),
}

// The errors become `MachineStop` with plain strings when being raised.
Expand All @@ -46,6 +47,7 @@ impl fmt::Display for ConstEvalErrKind {
Panic { msg, line, col, file } => {
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col)
}
Abort(ref msg) => write!(f, "{}", msg),
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_mir/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
None => match intrinsic_name {
sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
sym::unreachable => throw_ub!(Unreachable),
sym::abort => M::abort(self)?,
sym::abort => M::abort(self, "aborted execution".to_owned())?,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What message do we want here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd vote for "the program aborted execution".

// Unsupported diverging intrinsic.
_ => return Ok(false),
},
Expand Down Expand Up @@ -407,6 +407,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::transmute => {
self.copy_op_transmute(args[0], dest)?;
}
sym::assert_inhabited => {
let ty = instance.substs.type_at(0);
let layout = self.layout_of(ty)?;

if layout.abi.is_uninhabited() {
M::abort(self, format!("attempted to instantiate uninhabited type `{}`", ty))?;
}
}
sym::simd_insert => {
let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
let elem = args[2];
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_mir/src/interpret/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,10 @@ pub trait Machine<'mir, 'tcx>: Sized {
) -> InterpResult<'tcx>;

/// Called to evaluate `Abort` MIR terminator.
fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> {
throw_unsup_format!("aborting execution is not supported")
fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> {
use crate::const_eval::ConstEvalErrKind;

Err(ConstEvalErrKind::Abort(msg).into())
}

/// Called for all binary operations where the LHS has pointer type.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir/src/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}

Abort => {
M::abort(self)?;
M::abort(self, "aborted execution".to_owned())?;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What message do we want here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same as in the other place, I'd say.

}

// When we encounter Resume, we've finished unwinding
Expand Down
1 change: 1 addition & 0 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ extern "rust-intrinsic" {
/// This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_assert_type", issue = "none")]
pub fn assert_inhabited<T>();

/// A guard for unsafe functions that cannot ever be executed if `T` does not permit
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
#![feature(asm)]
#![feature(cfg_target_has_atomic)]
#![feature(const_alloc_layout)]
#![feature(const_assert_type)]
#![feature(const_discriminant)]
#![feature(const_cell_into_inner)]
#![feature(const_checked_int_methods)]
Expand All @@ -92,6 +93,7 @@
#![feature(const_ptr_offset)]
#![feature(const_ptr_offset_from)]
#![feature(const_raw_ptr_comparison)]
#![feature(const_raw_ptr_deref)]
#![feature(const_slice_from_raw_parts)]
#![feature(const_slice_ptr_len)]
#![feature(const_size_of_val)]
Expand All @@ -100,6 +102,7 @@
#![feature(const_type_name)]
#![feature(const_likely)]
#![feature(const_unreachable_unchecked)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(custom_inner_attributes)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
Expand Down
12 changes: 8 additions & 4 deletions library/core/src/mem/maybe_uninit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,9 @@ impl<T> MaybeUninit<T> {
/// let data = read(&mut buf);
/// ```
#[unstable(feature = "maybe_uninit_uninit_array", issue = "none")]
#[rustc_const_unstable(feature = "maybe_uninit_uninit_array", issue = "none")]
#[inline(always)]
pub fn uninit_array<const LEN: usize>() -> [Self; LEN] {
pub const fn uninit_array<const LEN: usize>() -> [Self; LEN] {
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
unsafe { MaybeUninit::<[MaybeUninit<T>; LEN]>::uninit().assume_init() }
}
Expand Down Expand Up @@ -503,9 +504,10 @@ impl<T> MaybeUninit<T> {
/// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️
/// ```
#[stable(feature = "maybe_uninit", since = "1.36.0")]
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
#[inline(always)]
#[rustc_diagnostic_item = "assume_init"]
pub unsafe fn assume_init(self) -> T {
pub const unsafe fn assume_init(self) -> T {
// SAFETY: the caller must guarantee that `self` is initialized.
// This also means that `self` must be a `value` variant.
unsafe {
Expand Down Expand Up @@ -810,8 +812,9 @@ impl<T> MaybeUninit<T> {
///
/// [`assume_init_ref`]: MaybeUninit::assume_init_ref
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
#[inline(always)]
pub unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] {
pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] {
// SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that
// `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`.
// The pointer obtained is valid since it refers to memory owned by `slice` which is a
Expand All @@ -831,8 +834,9 @@ impl<T> MaybeUninit<T> {
///
/// [`assume_init_mut`]: MaybeUninit::assume_init_mut
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
#[inline(always)]
pub unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] {
pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] {
// SAFETY: similar to safety notes for `slice_get_ref`, but we have a
// mutable reference which is also guaranteed to be valid for writes.
unsafe { &mut *(slice as *mut [Self] as *mut [T]) }
Expand Down
2 changes: 2 additions & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#![feature(cfg_target_has_atomic)]
#![feature(const_assume)]
#![feature(const_cell_into_inner)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(core_intrinsics)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
Expand Down Expand Up @@ -53,6 +54,7 @@
#![feature(const_pin)]
#![feature(const_slice_from_raw_parts)]
#![feature(const_raw_ptr_deref)]
#![feature(const_assert_type)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(option_unwrap_none)]
Expand Down
17 changes: 17 additions & 0 deletions library/core/tests/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,20 @@ fn test_discriminant_send_sync() {
is_send_sync::<Discriminant<Regular>>();
is_send_sync::<Discriminant<NotSendSync>>();
}

#[test]
fn assume_init_good() {
const TRUE: bool = unsafe { MaybeUninit::<bool>::new(true).assume_init() };

assert!(TRUE);
}

#[test]
fn assume_init_bad() {
const _BAD: () = unsafe {
MaybeUninit::<!>::uninit().assume_init();
//~^ ERROR the type `!` does not permit being left uninitialized
//~| ERROR this code causes undefined behavior when executed
//~| ERROR help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
};
}