From 8bd80e25f0bdb7a3282fecee148afed966067f1e Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 02:32:10 +0100 Subject: [PATCH 01/16] Make some of MaybeUninit's methods const --- .../rustc_mir/src/interpret/intrinsics.rs | 24 +++++++++++++++++++ library/core/src/intrinsics.rs | 1 + library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 7 ++++-- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index f666a89ca56de..c751f4f7eb6c6 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -407,6 +407,30 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::transmute => { self.copy_op_transmute(args[0], dest)?; } + sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { + let ty = instance.substs.type_at(0); + let layout = self.layout_of(ty)?; + + if layout.abi.is_uninhabited() { + throw_ub_format!("attempted to instantiate uninhabited type `{}`", ty); + } + if intrinsic_name == sym::assert_zero_valid + && !layout.might_permit_raw_init(self, /*zero:*/ true).unwrap() + { + throw_ub_format!( + "attempted to zero-initialize type `{}`, which is invalid", + ty + ); + } + if intrinsic_name == sym::assert_uninit_valid + && !layout.might_permit_raw_init(self, /*zero:*/ false).unwrap() + { + throw_ub_format!( + "attempted to leave type `{}` uninitialized, which is invalid", + ty + ); + } + } sym::simd_insert => { let index = u64::from(self.read_scalar(args[1])?.to_u32()?); let elem = args[2]; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 1a588b314c4f1..c0fcfb3a13952 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -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_maybe_assume_init", issue = "none")] pub fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e3b004be39afb..5d56a22bfa53a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -100,6 +100,7 @@ #![feature(const_type_name)] #![feature(const_likely)] #![feature(const_unreachable_unchecked)] +#![feature(const_maybe_assume_init)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 1924720b949f8..cb32c909717a4 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -314,8 +314,10 @@ impl MaybeUninit { /// let data = read(&mut buf); /// ``` #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_allow_const_fn_unstable(const_maybe_assume_init)] #[inline(always)] - pub fn uninit_array() -> [Self; LEN] { + pub const fn uninit_array() -> [Self; LEN] { // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. unsafe { MaybeUninit::<[MaybeUninit; LEN]>::uninit().assume_init() } } @@ -503,9 +505,10 @@ impl MaybeUninit { /// // `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_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 { From 91772c35c83f369283838ab049712a5f746e11ef Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 03:01:18 +0100 Subject: [PATCH 02/16] Even more const --- library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5d56a22bfa53a..a901375a958ab 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -92,6 +92,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)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index cb32c909717a4..6251355b90999 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -813,8 +813,9 @@ impl MaybeUninit { /// /// [`assume_init_ref`]: MaybeUninit::assume_init_ref #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_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 @@ -834,8 +835,9 @@ impl MaybeUninit { /// /// [`assume_init_mut`]: MaybeUninit::assume_init_mut #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_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]) } @@ -843,15 +845,17 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } } From 1ef5dbe7167376be7a0babefb0b4971d703e4b5d Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 16:17:37 +0100 Subject: [PATCH 03/16] Resolved some of the comments * Undo fn -> const fn for some fns. * Split feature gate. * Made all three intrinsics const --- library/core/src/intrinsics.rs | 4 +++- library/core/src/lib.rs | 3 ++- library/core/src/mem/maybe_uninit.rs | 15 ++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index c0fcfb3a13952..0c37bec469875 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -815,19 +815,21 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit /// zero-initialization: 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_zero_valid(); /// A guard for unsafe functions that cannot ever be executed if `T` has invalid /// bit patterns: 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_uninit_valid(); /// Gets a reference to a static `Location` indicating where it was called. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a901375a958ab..fc44a5a55fb59 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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)] @@ -101,7 +102,7 @@ #![feature(const_type_name)] #![feature(const_likely)] #![feature(const_unreachable_unchecked)] -#![feature(const_maybe_assume_init)] +#![feature(const_maybe_uninit_assume_init)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 6251355b90999..eddfff6f513a0 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -314,8 +314,7 @@ impl MaybeUninit { /// let data = read(&mut buf); /// ``` #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] - #[rustc_allow_const_fn_unstable(const_maybe_assume_init)] + #[rustc_const_unstable(feature = "maybe_uninit_uninit_array", issue = "none")] #[inline(always)] pub const fn uninit_array() -> [Self; LEN] { // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. @@ -505,7 +504,7 @@ impl MaybeUninit { /// // `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_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] #[rustc_diagnostic_item = "assume_init"] pub const unsafe fn assume_init(self) -> T { @@ -813,7 +812,7 @@ impl MaybeUninit { /// /// [`assume_init_ref`]: MaybeUninit::assume_init_ref #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] 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 @@ -835,7 +834,7 @@ impl MaybeUninit { /// /// [`assume_init_mut`]: MaybeUninit::assume_init_mut #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] 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 @@ -845,17 +844,15 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } } From f311db100ba338d13a6f590288e027623a8e9434 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 19:14:10 +0100 Subject: [PATCH 04/16] Added tests for assume_init --- library/core/tests/mem.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 59588d97787b7..7822c69d10b35 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -129,3 +129,21 @@ fn test_discriminant_send_sync() { is_send_sync::>(); is_send_sync::>(); } + +#[test] +fn assume_init_good() { + const TRUE: bool = { + let mut x = MaybeUninit::::uninit(); + x.as_mut_ptr().write(true); + x.assume_init() + }; + assert!(TRUE); +} + +#[test] +#[should_panic] +fn assume_init_bad() { + const BAD: () = { + MaybeUninit::::uninit().assume_init(); + }; +} From 4f9fd2a5d45a0ea0c49a3a78f8f1c8e091b9c604 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 21:07:40 +0100 Subject: [PATCH 05/16] Undo fn -> const fn for all intrinsics but assert_inhabited --- compiler/rustc_mir/src/interpret/intrinsics.rs | 18 +----------------- library/core/src/intrinsics.rs | 2 -- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index c751f4f7eb6c6..90018673e1a8a 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -407,29 +407,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::transmute => { self.copy_op_transmute(args[0], dest)?; } - sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { + sym::assert_inhabited => { let ty = instance.substs.type_at(0); let layout = self.layout_of(ty)?; if layout.abi.is_uninhabited() { throw_ub_format!("attempted to instantiate uninhabited type `{}`", ty); } - if intrinsic_name == sym::assert_zero_valid - && !layout.might_permit_raw_init(self, /*zero:*/ true).unwrap() - { - throw_ub_format!( - "attempted to zero-initialize type `{}`, which is invalid", - ty - ); - } - if intrinsic_name == sym::assert_uninit_valid - && !layout.might_permit_raw_init(self, /*zero:*/ false).unwrap() - { - throw_ub_format!( - "attempted to leave type `{}` uninitialized, which is invalid", - ty - ); - } } sym::simd_insert => { let index = u64::from(self.read_scalar(args[1])?.to_u32()?); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 0c37bec469875..ac31476f227e3 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -822,14 +822,12 @@ 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_type", issue = "none")] pub fn assert_zero_valid(); /// A guard for unsafe functions that cannot ever be executed if `T` has invalid /// bit patterns: 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_uninit_valid(); /// Gets a reference to a static `Location` indicating where it was called. From d366ed2730ed4a11df8a18f440c6874f7fa610f2 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 5 Dec 2020 17:32:19 +0100 Subject: [PATCH 06/16] abort() now takes a msg parameter --- compiler/rustc_mir/src/const_eval/error.rs | 2 ++ compiler/rustc_mir/src/interpret/intrinsics.rs | 4 ++-- compiler/rustc_mir/src/interpret/machine.rs | 6 ++++-- compiler/rustc_mir/src/interpret/terminator.rs | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 39358e03e7590..345a3d7e79bc2 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -20,6 +20,7 @@ pub enum ConstEvalErrKind { ModifiedGlobal, AssertFailure(AssertKind), Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, + Abort(String), } // The errors become `MachineStop` with plain strings when being raised. @@ -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) } } } diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 90018673e1a8a..18abf4291b1e2 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -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())?, // Unsupported diverging intrinsic. _ => return Ok(false), }, @@ -412,7 +412,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of(ty)?; if layout.abi.is_uninhabited() { - throw_ub_format!("attempted to instantiate uninhabited type `{}`", ty); + M::abort(self, format!("attempted to instantiate uninhabited type `{}`", ty))?; } } sym::simd_insert => { diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 66dbacb2f9d4d..1c13cdbc6e67d 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -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. diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index bb11c2a23bd81..18079488c8913 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -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())?; } // When we encounter Resume, we've finished unwinding From 7bd754cf8ca8e4b673f5432c837150b53c8d713d Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 5 Dec 2020 18:39:10 +0100 Subject: [PATCH 07/16] Fix tests (hopefully) --- compiler/rustc_mir/src/const_eval/error.rs | 2 +- library/core/tests/mem.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 345a3d7e79bc2..0e610e3755222 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -47,7 +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) + Abort(ref msg) => write!(f, "{}", msg), } } } diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 7822c69d10b35..f2e441de30bbb 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -132,7 +132,7 @@ fn test_discriminant_send_sync() { #[test] fn assume_init_good() { - const TRUE: bool = { + const TRUE: bool = unsafe { let mut x = MaybeUninit::::uninit(); x.as_mut_ptr().write(true); x.assume_init() @@ -143,7 +143,7 @@ fn assume_init_good() { #[test] #[should_panic] fn assume_init_bad() { - const BAD: () = { + const BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); }; } From 94762417e8957caa5db219e11be58c4de5def4c6 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 5 Dec 2020 19:37:03 +0100 Subject: [PATCH 08/16] Still unable to get the tests working --- library/core/tests/lib.rs | 2 ++ library/core/tests/mem.rs | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 106c9fe5da3e6..9e7a8189c8162 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -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)] @@ -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)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index f2e441de30bbb..4ebcf27e17345 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -132,18 +132,17 @@ fn test_discriminant_send_sync() { #[test] fn assume_init_good() { - const TRUE: bool = unsafe { - let mut x = MaybeUninit::::uninit(); - x.as_mut_ptr().write(true); - x.assume_init() - }; + const TRUE: bool = unsafe { MaybeUninit::::new(true).assume_init() }; + assert!(TRUE); } #[test] -#[should_panic] fn assume_init_bad() { - const BAD: () = unsafe { + 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` instead, and only call `assume_init` after initialization is done }; } From 4255a5afd5d55532fda11f43ded5339ad27ea27e Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 19:01:03 +0100 Subject: [PATCH 09/16] Moved failing test to src/test/ui/ Still have not figured out how to make it work --- library/core/tests/mem.rs | 11 +------ src/test/ui/assume-type-intrinsics.rs | 13 ++++++++ src/test/ui/assume-type-intrinsics.stderr | 37 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/assume-type-intrinsics.rs create mode 100644 src/test/ui/assume-type-intrinsics.stderr diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 4ebcf27e17345..268c2ed283f64 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -131,18 +131,9 @@ fn test_discriminant_send_sync() { } #[test] +#[cfg(not(bootstrap))] fn assume_init_good() { const TRUE: bool = unsafe { MaybeUninit::::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` instead, and only call `assume_init` after initialization is done - }; -} diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/assume-type-intrinsics.rs new file mode 100644 index 0000000000000..95562f3134fc8 --- /dev/null +++ b/src/test/ui/assume-type-intrinsics.rs @@ -0,0 +1,13 @@ +#![feature(never_type)] +#![feature(const_maybe_uninit_assume_init)] + +fn main() { + use std::mem::MaybeUninit; + + const _BAD: () = unsafe { + MaybeUninit::::uninit().assume_init(); + //~^ ERROR: the type `!` does not permit being left uninitialized + //~| this code causes undefined behavior when executed + //~| WARN: the type `!` does not permit being left uninitialized + }; +} diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/assume-type-intrinsics.stderr new file mode 100644 index 0000000000000..be45d1ba384ea --- /dev/null +++ b/src/test/ui/assume-type-intrinsics.stderr @@ -0,0 +1,37 @@ +error: any use of this value will cause an error + --> $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL + | +LL | intrinsics::assert_inhabited::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | attempted to instantiate uninhabited type `!` + | inside `MaybeUninit::::assume_init` at $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL + | inside `_BAD` at $DIR/assume-type-intrinsics.rs:8:9 + | + ::: $DIR/assume-type-intrinsics.rs:7:5 + | +LL | / const _BAD: () = unsafe { +LL | | MaybeUninit::::uninit().assume_init(); +LL | | +LL | | +LL | | +LL | | +LL | | }; + | |______- + | + = note: `#[deny(const_err)]` on by default + +warning: the type `!` does not permit being left uninitialized + --> $DIR/assume-type-intrinsics.rs:8:9 + | +LL | MaybeUninit::::uninit().assume_init(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: `#[warn(invalid_value)]` on by default + = note: the `!` type has no valid value + +error: aborting due to previous error; 1 warning emitted + From 3282b549acbb5922889329cddecd3dec700c54c2 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 19:29:35 +0100 Subject: [PATCH 10/16] Tests finally working --- src/test/ui/assume-type-intrinsics.rs | 4 +--- src/test/ui/assume-type-intrinsics.stderr | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/assume-type-intrinsics.rs index 95562f3134fc8..8e9cb33452749 100644 --- a/src/test/ui/assume-type-intrinsics.rs +++ b/src/test/ui/assume-type-intrinsics.rs @@ -6,8 +6,6 @@ fn main() { const _BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); - //~^ ERROR: the type `!` does not permit being left uninitialized - //~| this code causes undefined behavior when executed - //~| WARN: the type `!` does not permit being left uninitialized + //~^ WARN: the type `!` does not permit being left uninitialized }; } diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/assume-type-intrinsics.stderr index be45d1ba384ea..b776915affdb6 100644 --- a/src/test/ui/assume-type-intrinsics.stderr +++ b/src/test/ui/assume-type-intrinsics.stderr @@ -13,9 +13,6 @@ LL | intrinsics::assert_inhabited::(); LL | / const _BAD: () = unsafe { LL | | MaybeUninit::::uninit().assume_init(); LL | | -LL | | -LL | | -LL | | LL | | }; | |______- | From 345f230df98cb695ee092bdec5ce8d4154668c0f Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 20:25:13 +0100 Subject: [PATCH 11/16] Fix comments related to abort() --- compiler/rustc_mir/src/const_eval/machine.rs | 4 ++++ compiler/rustc_mir/src/interpret/intrinsics.rs | 2 +- compiler/rustc_mir/src/interpret/machine.rs | 6 ++---- compiler/rustc_mir/src/interpret/terminator.rs | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index c72089ec55a99..03ad2607692d3 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -333,6 +333,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Err(ConstEvalErrKind::AssertFailure(err).into()) } + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + Err(ConstEvalErrKind::Abort(msg).into()) + } + fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> { Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into()) } diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 18abf4291b1e2..c25a312bb5af8 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -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, "aborted execution".to_owned())?, + sym::abort => M::abort(self, "the program aborted execution".to_owned())?, // Unsupported diverging intrinsic. _ => return Ok(false), }, diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 1c13cdbc6e67d..2626afdf03309 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -176,10 +176,8 @@ pub trait Machine<'mir, 'tcx>: Sized { ) -> InterpResult<'tcx>; /// Called to evaluate `Abort` MIR terminator. - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { - use crate::const_eval::ConstEvalErrKind; - - Err(ConstEvalErrKind::Abort(msg).into()) + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> { + throw_unsup_format!("aborting execution is not supported") } /// Called for all binary operations where the LHS has pointer type. diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index 18079488c8913..a2931325a2863 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Abort => { - M::abort(self, "aborted execution".to_owned())?; + M::abort(self, "the program aborted execution".to_owned())?; } // When we encounter Resume, we've finished unwinding From d0a1e40eae2bb02b23b65c33918fce20e9ed4ae4 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 22:29:13 +0100 Subject: [PATCH 12/16] Remove unused feature gate --- library/core/tests/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 9e7a8189c8162..2aa3598a0d94f 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -54,7 +54,6 @@ #![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)] From bdda98aaba493be28569083c5ac57629caf3504d Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Mon, 7 Dec 2020 18:59:10 +0100 Subject: [PATCH 13/16] Add comment for assert_inhabited in compiler/rustc_mir/src/interpret/intrinsics.rs Co-authored-by: Ralf Jung --- compiler/rustc_mir/src/interpret/intrinsics.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index c25a312bb5af8..2ffb7a05f25c0 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -412,6 +412,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of(ty)?; if layout.abi.is_uninhabited() { + // The run-time intrinsic panics just to get a good backtrace; here we abort + // since there is no problem showing a backtrace even for aborts. M::abort(self, format!("attempted to instantiate uninhabited type `{}`", ty))?; } } From 69ab0bcabff34b97cd8fe9f0c741748a9ffc8928 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Mon, 7 Dec 2020 21:26:09 +0100 Subject: [PATCH 14/16] Use 'error-pattern' in ui test --- src/test/ui/assume-type-intrinsics.rs | 4 +++- src/test/ui/assume-type-intrinsics.stderr | 19 +++---------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/assume-type-intrinsics.rs index 8e9cb33452749..77370e1ccc59e 100644 --- a/src/test/ui/assume-type-intrinsics.rs +++ b/src/test/ui/assume-type-intrinsics.rs @@ -1,11 +1,13 @@ +// error-pattern: any use of this value will cause an error + #![feature(never_type)] #![feature(const_maybe_uninit_assume_init)] +#[allow(invalid_value)] fn main() { use std::mem::MaybeUninit; const _BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); - //~^ WARN: the type `!` does not permit being left uninitialized }; } diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/assume-type-intrinsics.stderr index b776915affdb6..6f400086a548c 100644 --- a/src/test/ui/assume-type-intrinsics.stderr +++ b/src/test/ui/assume-type-intrinsics.stderr @@ -6,29 +6,16 @@ LL | intrinsics::assert_inhabited::(); | | | attempted to instantiate uninhabited type `!` | inside `MaybeUninit::::assume_init` at $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL - | inside `_BAD` at $DIR/assume-type-intrinsics.rs:8:9 + | inside `_BAD` at $DIR/assume-type-intrinsics.rs:11:9 | - ::: $DIR/assume-type-intrinsics.rs:7:5 + ::: $DIR/assume-type-intrinsics.rs:10:5 | LL | / const _BAD: () = unsafe { LL | | MaybeUninit::::uninit().assume_init(); -LL | | LL | | }; | |______- | = note: `#[deny(const_err)]` on by default -warning: the type `!` does not permit being left uninitialized - --> $DIR/assume-type-intrinsics.rs:8:9 - | -LL | MaybeUninit::::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: `#[warn(invalid_value)]` on by default - = note: the `!` type has no valid value - -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error From 174935988f131efcbce3c63924ee056940c36fb5 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 8 Dec 2020 00:05:26 +0100 Subject: [PATCH 15/16] Make assume_init_{ref,mut} const --- library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index fc44a5a55fb59..06195ac628563 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -103,6 +103,7 @@ #![feature(const_likely)] #![feature(const_unreachable_unchecked)] #![feature(const_maybe_uninit_assume_init)] +#![feature(const_maybe_uninit_as_ptr)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index eddfff6f513a0..57ebab3318862 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -668,13 +668,14 @@ impl MaybeUninit { /// } /// ``` #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn assume_init_ref(&self) -> &T { + pub const unsafe fn assume_init_ref(&self) -> &T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::(); - &*self.value + &*self.as_ptr() } } @@ -790,13 +791,14 @@ impl MaybeUninit { // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make // a final decision about the rules before stabilization. #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn assume_init_mut(&mut self) -> &mut T { + pub const unsafe fn assume_init_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::(); - &mut *self.value + &mut *self.as_mut_ptr() } } From 077527170bd112d97bdbb288ae8771930bcaa5b7 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 8 Dec 2020 00:07:34 +0100 Subject: [PATCH 16/16] Make write and slice_as_[mut_]_ptr const --- library/core/src/mem/maybe_uninit.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 57ebab3318862..8800d7714cf47 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -373,8 +373,9 @@ impl MaybeUninit { /// skip running the destructor. For your convenience, this also returns a mutable /// reference to the (now safely initialized) contents of `self`. #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub fn write(&mut self, val: T) -> &mut T { + pub const fn write(&mut self, val: T) -> &mut T { *self = MaybeUninit::new(val); // SAFETY: We just initialized this value. unsafe { self.assume_init_mut() } @@ -846,15 +847,17 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } }