]> git.lizzy.rs Git - rust.git/commitdiff
panic when calling MaybeUninhabited::into_inner on uninhabited type
authorRalf Jung <post@ralfj.de>
Thu, 27 Dec 2018 08:40:33 +0000 (09:40 +0100)
committerRalf Jung <post@ralfj.de>
Thu, 27 Dec 2018 12:04:53 +0000 (13:04 +0100)
src/libcore/intrinsics.rs
src/libcore/mem.rs
src/librustc_codegen_ssa/mir/block.rs
src/librustc_typeck/check/intrinsic.rs
src/test/run-pass/panic-uninitialized-zeroed.rs

index 7508257f7806f629b17b0da4cfeb4ee7db6117b0..4f5310f5285c9956207887de18ae22a5126053bf 100644 (file)
     /// 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,
index c024868714cab119f9e35d64146475f9817eb75f..8fcbb73d9ce462eaa0090ccf9d11ff9a6dba59cd 100644 (file)
@@ -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 @@ pub fn set(&mut self, val: 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)
     }
 
index 7397c722df6c91f7897ced1241d5579ad1c21463..de824322263d728e1f242b7d746724220c04503a 100644 (file)
@@ -500,53 +500,62 @@ fn funclet_closure_factory<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
                     _ => 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 = match callee.layout.ty.sty {
+                        ty::FnDef(_, substs) => {
+                            substs.type_at(0)
+                        }
+                        _ => bug!("{} is not callable as intrinsic", callee.layout.ty)
+                    };
+                    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;
                 }
 
index c80990a0704bd58a93f88c9d0005dbb6a5cb65a1..eb6ebbe0e96a18f2c46d9db2479e18c5862a3d68 100644 (file)
@@ -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()),
index c806bb97c1519bef4ac41bbd3c9d83a6f0ee389f..d47ff6c630d1194abebf6ef7ddd6f78bec9992ea 100644 (file)
@@ -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)
         );