about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-01-05 14:58:57 +0000
committerbors <bors@rust-lang.org>2019-01-05 14:58:57 +0000
commit8c2d0f4a1da300cb34d77fbcdd9f7209cc556582 (patch)
tree0401cf1c7bb2474333a26b2d22c5b28fe52d3dae /src
parent68614265d312fc2cbe8a696f7dabb9416eb6f221 (diff)
parentc118b17953a8e29b850b8ed8fe0d3aaf2917a9da (diff)
downloadrust-8c2d0f4a1da300cb34d77fbcdd9f7209cc556582.tar.gz
rust-8c2d0f4a1da300cb34d77fbcdd9f7209cc556582.zip
Auto merge of #57145 - RalfJung:panic-if-uninhabited, r=alexcrichton
panic when calling MaybeUninhabited::into_inner on uninhabited type

I do this by adding an internal-only intrinsic `panic_if_uninhabited`. I have no idea what I am doing here, just mindlessly copying code around, so please review carefully!
Diffstat (limited to 'src')
-rw-r--r--src/libcore/intrinsics.rs5
-rw-r--r--src/libcore/mem.rs6
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs96
-rw-r--r--src/librustc_typeck/check/intrinsic.rs1
-rw-r--r--src/test/run-pass/panic-uninitialized-zeroed.rs41
5 files changed, 96 insertions, 53 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 7508257f780..4f5310f5285 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -690,6 +690,11 @@ extern "rust-intrinsic" {
     /// crate it is invoked in.
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
+    /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
+    /// This will statically either panic, or do nothing.
+    #[cfg(not(stage0))]
+    pub fn panic_if_uninhabited<T>();
+
     /// Creates a value initialized to zero.
     ///
     /// `init` is unsafe because it returns a zeroed-out datum,
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index c024868714c..8fcbb73d9ce 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -492,6 +492,8 @@ pub const fn needs_drop<T>() -> bool {
 #[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::zeroed` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn zeroed<T>() -> T {
+    #[cfg(not(stage0))]
+    intrinsics::panic_if_uninhabited::<T>();
     intrinsics::init()
 }
 
@@ -624,6 +626,8 @@ pub unsafe fn zeroed<T>() -> T {
 #[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninitialized` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn uninitialized<T>() -> T {
+    #[cfg(not(stage0))]
+    intrinsics::panic_if_uninhabited::<T>();
     intrinsics::uninit()
 }
 
@@ -1128,6 +1132,8 @@ impl<T> MaybeUninit<T> {
     #[unstable(feature = "maybe_uninit", issue = "53491")]
     #[inline(always)]
     pub unsafe fn into_inner(self) -> T {
+        #[cfg(not(stage0))]
+        intrinsics::panic_if_uninhabited::<T>();
         ManuallyDrop::into_inner(self.value)
     }
 
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 7397c722df6..aa82c853257 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -500,53 +500,57 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     _ => bx.new_fn_type(sig, &extra_args)
                 };
 
-                // emit a panic instead of instantiating an uninhabited type
-                if (intrinsic == Some("init") || intrinsic == Some("uninit")) &&
-                    fn_ty.ret.layout.abi.is_uninhabited()
-                {
-                    let loc = bx.sess().source_map().lookup_char_pos(span.lo());
-                    let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
-                    let filename = bx.const_str_slice(filename);
-                    let line = bx.const_u32(loc.line as u32);
-                    let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
-                    let align = tcx.data_layout.aggregate_align.abi
-                        .max(tcx.data_layout.i32_align.abi)
-                        .max(tcx.data_layout.pointer_align.abi);
-
-                    let str = format!(
-                        "Attempted to instantiate uninhabited type {} using mem::{}",
-                        sig.output(),
-                        if intrinsic == Some("init") { "zeroed" } else { "uninitialized" }
-                    );
-                    let msg_str = Symbol::intern(&str).as_str();
-                    let msg_str = bx.const_str_slice(msg_str);
-                    let msg_file_line_col = bx.const_struct(
-                        &[msg_str, filename, line, col],
-                        false,
-                    );
-                    let msg_file_line_col = bx.static_addr_of(
-                        msg_file_line_col,
-                        align,
-                        Some("panic_loc"),
-                    );
+                // emit a panic or a NOP 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 loc = bx.sess().source_map().lookup_char_pos(span.lo());
+                        let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
+                        let filename = bx.const_str_slice(filename);
+                        let line = bx.const_u32(loc.line as u32);
+                        let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
+                        let align = tcx.data_layout.aggregate_align.abi
+                            .max(tcx.data_layout.i32_align.abi)
+                            .max(tcx.data_layout.pointer_align.abi);
+
+                        let str = format!(
+                            "Attempted to instantiate uninhabited type {}",
+                            ty
+                        );
+                        let msg_str = Symbol::intern(&str).as_str();
+                        let msg_str = bx.const_str_slice(msg_str);
+                        let msg_file_line_col = bx.const_struct(
+                            &[msg_str, filename, line, col],
+                            false,
+                        );
+                        let msg_file_line_col = bx.static_addr_of(
+                            msg_file_line_col,
+                            align,
+                            Some("panic_loc"),
+                        );
 
-                    // 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_ty = bx.fn_type_of_instance(&instance);
-                    let llfn = bx.get_fn(instance);
-
-                    // Codegen the actual panic invoke/call.
-                    do_call(
-                        self,
-                        &mut bx,
-                        fn_ty,
-                        llfn,
-                        &[msg_file_line_col],
-                        destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
-                        cleanup,
-                    );
+                        // 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_ty = bx.fn_type_of_instance(&instance);
+                        let llfn = bx.get_fn(instance);
+
+                        // Codegen the actual panic invoke/call.
+                        do_call(
+                            self,
+                            &mut bx,
+                            fn_ty,
+                            llfn,
+                            &[msg_file_line_col],
+                            destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
+                            cleanup,
+                        );
+                    } else {
+                        // a NOP
+                        funclet_br(self, &mut bx, destination.as_ref().unwrap().1);
+                    }
                     return;
                 }
 
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index a36b2192143..821c30b4fa7 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -133,6 +133,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                  ], tcx.types.usize)
             }
             "rustc_peek" => (1, vec![param(0)], param(0)),
+            "panic_if_uninhabited" => (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/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs
index c806bb97c15..d47ff6c630d 100644
--- a/src/test/run-pass/panic-uninitialized-zeroed.rs
+++ b/src/test/run-pass/panic-uninitialized-zeroed.rs
@@ -2,7 +2,7 @@
 // This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
 // in a runtime panic.
 
-#![feature(never_type)]
+#![feature(never_type, maybe_uninit)]
 
 use std::{mem, panic};
 
@@ -20,7 +20,7 @@ fn main() {
             panic::catch_unwind(|| {
                 mem::uninitialized::<!>()
             }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type ! using mem::uninitialized"
+                s == "Attempted to instantiate uninhabited type !"
             })),
             Some(true)
         );
@@ -29,7 +29,16 @@ fn main() {
             panic::catch_unwind(|| {
                 mem::zeroed::<!>()
             }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type ! using mem::zeroed"
+                s == "Attempted to instantiate uninhabited type !"
+            })),
+            Some(true)
+        );
+
+        assert_eq!(
+            panic::catch_unwind(|| {
+                mem::MaybeUninit::<!>::uninitialized().into_inner()
+            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
+                s == "Attempted to instantiate uninhabited type !"
             })),
             Some(true)
         );
@@ -38,7 +47,7 @@ fn main() {
             panic::catch_unwind(|| {
                 mem::uninitialized::<Foo>()
             }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Foo using mem::uninitialized"
+                s == "Attempted to instantiate uninhabited type Foo"
             })),
             Some(true)
         );
@@ -47,7 +56,16 @@ fn main() {
             panic::catch_unwind(|| {
                 mem::zeroed::<Foo>()
             }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Foo using mem::zeroed"
+                s == "Attempted to instantiate uninhabited type Foo"
+            })),
+            Some(true)
+        );
+
+        assert_eq!(
+            panic::catch_unwind(|| {
+                mem::MaybeUninit::<Foo>::uninitialized().into_inner()
+            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
+                s == "Attempted to instantiate uninhabited type Foo"
             })),
             Some(true)
         );
@@ -56,7 +74,7 @@ fn main() {
             panic::catch_unwind(|| {
                 mem::uninitialized::<Bar>()
             }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Bar using mem::uninitialized"
+                s == "Attempted to instantiate uninhabited type Bar"
             })),
             Some(true)
         );
@@ -65,7 +83,16 @@ fn main() {
             panic::catch_unwind(|| {
                 mem::zeroed::<Bar>()
             }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Bar using mem::zeroed"
+                s == "Attempted to instantiate uninhabited type Bar"
+            })),
+            Some(true)
+        );
+
+        assert_eq!(
+            panic::catch_unwind(|| {
+                mem::MaybeUninit::<Bar>::uninitialized().into_inner()
+            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
+                s == "Attempted to instantiate uninhabited type Bar"
             })),
             Some(true)
         );