about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-11 10:36:16 +0100
committerGitHub <noreply@github.com>2020-03-11 10:36:16 +0100
commita7c2eef2aeb23f52efc4a4bfd240292d43a61798 (patch)
treea794d20513cc74cde83c05adb18370dc879e629b /src
parent15812785344d913d779d9738fe3cca8de56f71d5 (diff)
parenta09c33e36205991bb633a848d1e9c7604ae43ce8 (diff)
downloadrust-a7c2eef2aeb23f52efc4a4bfd240292d43a61798.tar.gz
rust-a7c2eef2aeb23f52efc4a4bfd240292d43a61798.zip
Rollup merge of #66059 - RalfJung:panic-on-non-zero, r=eddyb
mem::zeroed/uninit: panic on types that do not permit zero-initialization

r? @eddyb @oli-obk

Cc https://github.com/rust-lang/rust/issues/62825

Also see [this summary comment](https://github.com/rust-lang/rust/pull/66059#issuecomment-586734747)
Diffstat (limited to 'src')
-rw-r--r--src/libcore/intrinsics.rs10
-rw-r--r--src/libcore/mem/mod.rs6
-rw-r--r--src/librustc/ty/layout.rs30
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs127
-rw-r--r--src/librustc_index/vec.rs2
-rw-r--r--src/librustc_target/abi/mod.rs85
-rw-r--r--src/librustc_target/lib.rs3
-rw-r--r--src/librustc_typeck/check/intrinsic.rs4
-rw-r--r--src/test/ui/intrinsics/panic-uninitialized-zeroed.rs170
-rw-r--r--src/test/ui/never_type/panic-uninitialized-zeroed.rs102
10 files changed, 370 insertions, 169 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index a889eff75c0..721a2d26a71 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1007,6 +1007,16 @@ extern "rust-intrinsic" {
     /// This will statically either panic, or do nothing.
     pub fn panic_if_uninhabited<T>();
 
+    /// 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.
+    #[cfg(not(bootstrap))]
+    pub fn panic_if_zero_invalid<T>();
+
+    /// A guard for unsafe functions that cannot ever be executed if `T` has invalid
+    /// bit patterns: This will statically either panic, or do nothing.
+    #[cfg(not(bootstrap))]
+    pub fn panic_if_any_invalid<T>();
+
     /// Gets a reference to a static `Location` indicating where it was called.
     #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")]
     pub fn caller_location() -> &'static crate::panic::Location<'static>;
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index 90144d11dc9..8add875dcbe 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -496,6 +496,9 @@ pub const fn needs_drop<T>() -> bool {
 #[allow(deprecated)]
 #[rustc_diagnostic_item = "mem_zeroed"]
 pub unsafe fn zeroed<T>() -> T {
+    #[cfg(not(bootstrap))]
+    intrinsics::panic_if_zero_invalid::<T>();
+    #[cfg(bootstrap)]
     intrinsics::panic_if_uninhabited::<T>();
     intrinsics::init()
 }
@@ -529,6 +532,9 @@ pub unsafe fn zeroed<T>() -> T {
 #[allow(deprecated)]
 #[rustc_diagnostic_item = "mem_uninitialized"]
 pub unsafe fn uninitialized<T>() -> T {
+    #[cfg(not(bootstrap))]
+    intrinsics::panic_if_any_invalid::<T>();
+    #[cfg(bootstrap)]
     intrinsics::panic_if_uninhabited::<T>();
     intrinsics::uninit()
 }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index e257b48f111..dedb3035ced 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1904,36 +1904,6 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
     }
 }
 
-pub trait MaybeResult<T> {
-    type Error;
-
-    fn from(x: Result<T, Self::Error>) -> Self;
-    fn to_result(self) -> Result<T, Self::Error>;
-}
-
-impl<T> MaybeResult<T> for T {
-    type Error = !;
-
-    fn from(x: Result<T, Self::Error>) -> Self {
-        let Ok(x) = x;
-        x
-    }
-    fn to_result(self) -> Result<T, Self::Error> {
-        Ok(self)
-    }
-}
-
-impl<T, E> MaybeResult<T> for Result<T, E> {
-    type Error = E;
-
-    fn from(x: Result<T, Self::Error>) -> Self {
-        x
-    }
-    fn to_result(self) -> Result<T, Self::Error> {
-        self
-    }
-}
-
 pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>;
 
 impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index a1b54607b80..c8d352cd2dd 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -434,6 +434,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup);
     }
 
+    /// Returns `true` if this is indeed a panic intrinsic and codegen is done.
+    fn codegen_panic_intrinsic(
+        &mut self,
+        helper: &TerminatorCodegenHelper<'tcx>,
+        bx: &mut Bx,
+        intrinsic: Option<&str>,
+        instance: Option<Instance<'tcx>>,
+        span: Span,
+        destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
+        cleanup: Option<mir::BasicBlock>,
+    ) -> bool {
+        // Emit a panic or a no-op for `panic_if_uninhabited`.
+        // These are intrinsics that compile to panics so that we can get a message
+        // which mentions the offending type, even from a const context.
+        #[derive(Debug, PartialEq)]
+        enum PanicIntrinsic {
+            IfUninhabited,
+            IfZeroInvalid,
+            IfAnyInvalid,
+        };
+        let panic_intrinsic = intrinsic.and_then(|i| match i {
+            // FIXME: Move to symbols instead of strings.
+            "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited),
+            "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid),
+            "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid),
+            _ => None,
+        });
+        if let Some(intrinsic) = panic_intrinsic {
+            use PanicIntrinsic::*;
+            let ty = instance.unwrap().substs.type_at(0);
+            let layout = bx.layout_of(ty);
+            let do_panic = match intrinsic {
+                IfUninhabited => layout.abi.is_uninhabited(),
+                // We unwrap as the error type is `!`.
+                IfZeroInvalid => !layout.might_permit_raw_init(bx, /*zero:*/ true).unwrap(),
+                // We unwrap as the error type is `!`.
+                IfAnyInvalid => !layout.might_permit_raw_init(bx, /*zero:*/ false).unwrap(),
+            };
+            if do_panic {
+                let msg_str = if layout.abi.is_uninhabited() {
+                    // Use this error even for the other intrinsics as it is more precise.
+                    format!("attempted to instantiate uninhabited type `{}`", ty)
+                } else if intrinsic == IfZeroInvalid {
+                    format!("attempted to zero-initialize type `{}`, which is invalid", ty)
+                } else {
+                    format!("attempted to leave type `{}` uninitialized, which is invalid", ty)
+                };
+                let msg = bx.const_str(Symbol::intern(&msg_str));
+                let location = self.get_caller_location(bx, span).immediate();
+
+                // Obtain the panic entry point.
+                // FIXME: dedup this with `codegen_assert_terminator` above.
+                let def_id =
+                    common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
+                let instance = ty::Instance::mono(bx.tcx(), def_id);
+                let fn_abi = FnAbi::of_instance(bx, instance, &[]);
+                let llfn = bx.get_fn_addr(instance);
+
+                if let Some((_, target)) = destination.as_ref() {
+                    helper.maybe_sideeffect(self.mir, bx, &[*target]);
+                }
+                // Codegen the actual panic invoke/call.
+                helper.do_call(
+                    self,
+                    bx,
+                    fn_abi,
+                    llfn,
+                    &[msg.0, msg.1, location],
+                    destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
+                    cleanup,
+                );
+            } else {
+                // a NOP
+                let target = destination.as_ref().unwrap().1;
+                helper.maybe_sideeffect(self.mir, bx, &[target]);
+                helper.funclet_br(self, bx, target)
+            }
+            true
+        } else {
+            false
+        }
+    }
+
     fn codegen_call_terminator(
         &mut self,
         helper: TerminatorCodegenHelper<'tcx>,
@@ -520,41 +603,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             bug!("`miri_start_panic` should never end up in compiled code");
         }
 
-        // Emit a panic or a no-op for `panic_if_uninhabited`.
-        if intrinsic == Some("panic_if_uninhabited") {
-            let ty = instance.unwrap().substs.type_at(0);
-            let layout = bx.layout_of(ty);
-            if layout.abi.is_uninhabited() {
-                let msg_str = format!("Attempted to instantiate uninhabited type {}", ty);
-                let msg = bx.const_str(Symbol::intern(&msg_str));
-                let location = self.get_caller_location(&mut bx, span).immediate();
-
-                // Obtain the panic entry point.
-                let def_id =
-                    common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
-                let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let fn_abi = FnAbi::of_instance(&bx, instance, &[]);
-                let llfn = bx.get_fn_addr(instance);
-
-                if let Some((_, target)) = destination.as_ref() {
-                    helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
-                }
-                // Codegen the actual panic invoke/call.
-                helper.do_call(
-                    self,
-                    &mut bx,
-                    fn_abi,
-                    llfn,
-                    &[msg.0, msg.1, location],
-                    destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
-                    cleanup,
-                );
-            } else {
-                // a NOP
-                let target = destination.as_ref().unwrap().1;
-                helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
-                helper.funclet_br(self, &mut bx, target)
-            }
+        if self.codegen_panic_intrinsic(
+            &helper,
+            &mut bx,
+            intrinsic,
+            instance,
+            span,
+            destination,
+            cleanup,
+        ) {
             return;
         }
 
diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs
index 1dfe97238a3..7020939fa20 100644
--- a/src/librustc_index/vec.rs
+++ b/src/librustc_index/vec.rs
@@ -196,7 +196,7 @@ macro_rules! newtype_index {
 
             #[inline]
             fn index(self) -> usize {
-                usize::from(self)
+                self.as_usize()
             }
         }
 
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index a3a9b542767..2f8bbd66c32 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -937,6 +937,7 @@ impl<'a, Ty> Deref for TyLayout<'a, Ty> {
     }
 }
 
+/// Trait for context types that can compute layouts of things.
 pub trait LayoutOf {
     type Ty;
     type TyLayout;
@@ -947,6 +948,38 @@ pub trait LayoutOf {
     }
 }
 
+/// The `TyLayout` above will always be a `MaybeResult<TyLayout<'_, Self>>`.
+/// We can't add the bound due to the lifetime, but this trait is still useful when
+/// writing code that's generic over the `LayoutOf` impl.
+pub trait MaybeResult<T> {
+    type Error;
+
+    fn from(x: Result<T, Self::Error>) -> Self;
+    fn to_result(self) -> Result<T, Self::Error>;
+}
+
+impl<T> MaybeResult<T> for T {
+    type Error = !;
+
+    fn from(Ok(x): Result<T, Self::Error>) -> Self {
+        x
+    }
+    fn to_result(self) -> Result<T, Self::Error> {
+        Ok(self)
+    }
+}
+
+impl<T, E> MaybeResult<T> for Result<T, E> {
+    type Error = E;
+
+    fn from(x: Result<T, Self::Error>) -> Self {
+        x
+    }
+    fn to_result(self) -> Result<T, Self::Error> {
+        self
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum PointerKind {
     /// Most general case, we know no restrictions to tell LLVM.
@@ -987,6 +1020,9 @@ impl<'a, Ty> TyLayout<'a, Ty> {
     {
         Ty::for_variant(self, cx, variant_index)
     }
+
+    /// Callers might want to use `C: LayoutOf<Ty=Ty, TyLayout: MaybeResult<Self>>`
+    /// to allow recursion (see `might_permit_zero_init` below for an example).
     pub fn field<C>(self, cx: &C, i: usize) -> C::TyLayout
     where
         Ty: TyLayoutMethods<'a, C>,
@@ -994,6 +1030,7 @@ impl<'a, Ty> TyLayout<'a, Ty> {
     {
         Ty::field(self, cx, i)
     }
+
     pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
     where
         Ty: TyLayoutMethods<'a, C>,
@@ -1017,4 +1054,52 @@ impl<'a, Ty> TyLayout<'a, Ty> {
             Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
         }
     }
+
+    /// Determines if this type permits "raw" initialization by just transmuting some
+    /// memory into an instance of `T`.
+    /// `zero` indicates if the memory is zero-initialized, or alternatively
+    /// left entirely uninitialized.
+    /// This is conservative: in doubt, it will answer `true`.
+    ///
+    /// FIXME: Once we removed all the conservatism, we could alternatively
+    /// create an all-0/all-undef constant and run the const value validator to see if
+    /// this is a valid value for the given type.
+    pub fn might_permit_raw_init<C, E>(self, cx: &C, zero: bool) -> Result<bool, E>
+    where
+        Self: Copy,
+        Ty: TyLayoutMethods<'a, C>,
+        C: LayoutOf<Ty = Ty, TyLayout: MaybeResult<Self, Error = E>> + HasDataLayout,
+    {
+        let scalar_allows_raw_init = move |s: &Scalar| -> bool {
+            if zero {
+                let range = &s.valid_range;
+                // The range must contain 0.
+                range.contains(&0) || (*range.start() > *range.end()) // wrap-around allows 0
+            } else {
+                // The range must include all values. `valid_range_exclusive` handles
+                // the wrap-around using target arithmetic; with wrap-around then the full
+                // range is one where `start == end`.
+                let range = s.valid_range_exclusive(cx);
+                range.start == range.end
+            }
+        };
+
+        // Check the ABI.
+        let valid = match &self.abi {
+            Abi::Uninhabited => false, // definitely UB
+            Abi::Scalar(s) => scalar_allows_raw_init(s),
+            Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
+            Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s),
+            Abi::Aggregate { .. } => true, // Cannot be excluded *right now*.
+        };
+        if !valid {
+            // This is definitely not okay.
+            trace!("might_permit_raw_init({:?}, zero={}): not valid", self.details, zero);
+            return Ok(false);
+        }
+
+        // If we have not found an error yet, we need to recursively descend.
+        // FIXME(#66151): For now, we are conservative and do not do this.
+        Ok(true)
+    }
 }
diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs
index 71150e74f70..3c397eb444d 100644
--- a/src/librustc_target/lib.rs
+++ b/src/librustc_target/lib.rs
@@ -10,6 +10,9 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(bool_to_option)]
 #![feature(nll)]
+#![feature(never_type)]
+#![feature(associated_type_bounds)]
+#![feature(exhaustive_patterns)]
 
 #[macro_use]
 extern crate log;
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 3572eda5c13..d2a358c3e09 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -147,7 +147,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             ),
             "rustc_peek" => (1, vec![param(0)], param(0)),
             "caller_location" => (0, vec![], tcx.caller_location_ty()),
-            "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
+            "panic_if_uninhabited" | "panic_if_zero_invalid" | "panic_if_any_invalid" => {
+                (1, Vec::new(), tcx.mk_unit())
+            }
             "init" => (1, Vec::new(), param(0)),
             "uninit" => (1, Vec::new(), param(0)),
             "forget" => (1, vec![param(0)], tcx.mk_unit()),
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
new file mode 100644
index 00000000000..02f8ecaa4ee
--- /dev/null
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -0,0 +1,170 @@
+// run-pass
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
+
+#![feature(never_type)]
+#![allow(deprecated, invalid_value)]
+
+use std::{
+    mem::{self, MaybeUninit, ManuallyDrop},
+    panic,
+    ptr::NonNull,
+    num,
+};
+
+#[allow(dead_code)]
+struct Foo {
+    x: u8,
+    y: !,
+}
+
+enum Bar {}
+
+#[allow(dead_code)]
+enum OneVariant { Variant(i32) }
+
+// An enum with ScalarPair layout
+#[allow(dead_code)]
+enum LR {
+    Left(i64),
+    Right(i64),
+}
+#[allow(dead_code, non_camel_case_types)]
+enum LR_NonZero {
+    Left(num::NonZeroI64),
+    Right(num::NonZeroI64),
+}
+
+fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
+    let err = panic::catch_unwind(op).err();
+    assert_eq!(
+        err.as_ref().and_then(|a| a.downcast_ref::<String>()).map(|s| &**s),
+        Some(msg)
+    );
+}
+
+fn main() {
+    unsafe {
+        // Uninhabited types
+        test_panic_msg(
+            || mem::uninitialized::<!>(),
+            "attempted to instantiate uninhabited type `!`"
+        );
+        test_panic_msg(
+            || mem::zeroed::<!>(),
+            "attempted to instantiate uninhabited type `!`"
+        );
+        test_panic_msg(
+            || MaybeUninit::<!>::uninit().assume_init(),
+            "attempted to instantiate uninhabited type `!`"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<Foo>(),
+            "attempted to instantiate uninhabited type `Foo`"
+        );
+        test_panic_msg(
+            || mem::zeroed::<Foo>(),
+            "attempted to instantiate uninhabited type `Foo`"
+        );
+        test_panic_msg(
+            || MaybeUninit::<Foo>::uninit().assume_init(),
+            "attempted to instantiate uninhabited type `Foo`"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<Bar>(),
+            "attempted to instantiate uninhabited type `Bar`"
+        );
+        test_panic_msg(
+            || mem::zeroed::<Bar>(),
+            "attempted to instantiate uninhabited type `Bar`"
+        );
+        test_panic_msg(
+            || MaybeUninit::<Bar>::uninit().assume_init(),
+            "attempted to instantiate uninhabited type `Bar`"
+        );
+
+        // Types that do not like zero-initialziation
+        test_panic_msg(
+            || mem::uninitialized::<fn()>(),
+            "attempted to leave type `fn()` uninitialized, which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<fn()>(),
+            "attempted to zero-initialize type `fn()`, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<*const dyn Send>(),
+            "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<*const dyn Send>(),
+            "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid"
+        );
+
+        /* FIXME(#66151) we conservatively do not error here yet.
+        test_panic_msg(
+            || mem::uninitialized::<LR_NonZero>(),
+            "attempted to leave type `LR_NonZero` uninitialized, which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<LR_NonZero>(),
+            "attempted to zero-initialize type `LR_NonZero`, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
+            "attempted to leave type `std::mem::ManuallyDrop<LR_NonZero>` uninitialized, \
+             which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
+            "attempted to zero-initialize type `std::mem::ManuallyDrop<LR_NonZero>`, \
+             which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
+            "attempted to leave type `(std::ptr::NonNull<u32>, u32, u32)` uninitialized, \
+                which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<(NonNull<u32>, u32, u32)>(),
+            "attempted to zero-initialize type `(std::ptr::NonNull<u32>, u32, u32)`, \
+                which is invalid"
+        );
+        */
+
+        // Types that can be zero, but not uninit.
+        test_panic_msg(
+            || mem::uninitialized::<bool>(),
+            "attempted to leave type `bool` uninitialized, which is invalid"
+        );
+        test_panic_msg(
+            || mem::uninitialized::<LR>(),
+            "attempted to leave type `LR` uninitialized, which is invalid"
+        );
+        test_panic_msg(
+            || mem::uninitialized::<ManuallyDrop<LR>>(),
+            "attempted to leave type `std::mem::ManuallyDrop<LR>` uninitialized, which is invalid"
+        );
+
+        // Some things that should work.
+        let _val = mem::zeroed::<bool>();
+        let _val = mem::zeroed::<LR>();
+        let _val = mem::zeroed::<ManuallyDrop<LR>>();
+        let _val = mem::zeroed::<OneVariant>();
+        let _val = mem::zeroed::<Option<&'static i32>>();
+        let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
+        let _val = mem::uninitialized::<MaybeUninit<bool>>();
+
+        // These are UB because they have not been officially blessed, but we await the resolution
+        // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
+        // anything about that.
+        let _val = mem::uninitialized::<i32>();
+        let _val = mem::uninitialized::<*const ()>();
+    }
+}
diff --git a/src/test/ui/never_type/panic-uninitialized-zeroed.rs b/src/test/ui/never_type/panic-uninitialized-zeroed.rs
deleted file mode 100644
index e0c30160b9e..00000000000
--- a/src/test/ui/never_type/panic-uninitialized-zeroed.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-// run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
-// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
-// in a runtime panic.
-
-#![feature(never_type)]
-#![allow(deprecated, invalid_value)]
-
-use std::{mem, panic};
-
-#[allow(dead_code)]
-struct Foo {
-    x: u8,
-    y: !,
-}
-
-enum Bar {}
-
-fn main() {
-    unsafe {
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::uninitialized::<!>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type !"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::zeroed::<!>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type !"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::MaybeUninit::<!>::uninit().assume_init()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type !"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::uninitialized::<Foo>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Foo"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::zeroed::<Foo>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Foo"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::MaybeUninit::<Foo>::uninit().assume_init()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Foo"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::uninitialized::<Bar>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Bar"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::zeroed::<Bar>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Bar"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::MaybeUninit::<Bar>::uninit().assume_init()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Bar"
-            })),
-            Some(true)
-        );
-    }
-}