about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJorge Aparicio <jorge@japaric.io>2018-08-19 17:36:04 +0200
committerRalf Jung <post@ralfj.de>2018-09-30 17:26:15 +0200
commitf9bbb5f31df8232fb1e17a3408b62590c30112c7 (patch)
tree9913308c26155b80c1b4decd46c80c39a635daeb /src
parent1886d5fe1cdd1a016ecea9fc93d68b3052c528c8 (diff)
downloadrust-f9bbb5f31df8232fb1e17a3408b62590c30112c7.tar.gz
rust-f9bbb5f31df8232fb1e17a3408b62590c30112c7.zip
panic when instantiating an uninhabited type via mem::{uninitialized,zeroed}
Diffstat (limited to 'src')
-rw-r--r--src/librustc_codegen_llvm/mir/block.rs49
-rw-r--r--src/librustc_target/abi/mod.rs8
-rw-r--r--src/test/run-pass/panic-uninitialized-zeroed.rs31
3 files changed, 88 insertions, 0 deletions
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index a534b4e478f..72fb9df6f81 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -463,6 +463,55 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     return;
                 }
 
+                if (intrinsic == Some("init") || intrinsic == Some("uninit")) &&
+                    bx.cx.layout_of(sig.output()).abi.is_uninhabited()
+                {
+                    let loc = bx.sess().codemap().lookup_char_pos(span.lo());
+                    let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
+                    let filename = C_str_slice(bx.cx, filename);
+                    let line = C_u32(bx.cx, loc.line as u32);
+                    let col = C_u32(bx.cx, loc.col.to_usize() as u32 + 1);
+                    let align = tcx.data_layout.aggregate_align
+                        .max(tcx.data_layout.i32_align)
+                        .max(tcx.data_layout.pointer_align);
+
+                    let str = if intrinsic == Some("init") {
+                        "Attempted to instantiate an uninhabited type (e.g. `!`) \
+                         using mem::zeroed()"
+                    } else {
+                        "Attempted to instantiate an uninhabited type (e.g. `!`) \
+                         using mem::uninitialized()"
+                    };
+                    let msg_str = Symbol::intern(str).as_str();
+                    let msg_str = C_str_slice(bx.cx, msg_str);
+                    let msg_file_line_col = C_struct(bx.cx,
+                                                    &[msg_str, filename, line, col],
+                                                    false);
+                    let msg_file_line_col = consts::addr_of(bx.cx,
+                                                            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 = FnType::of_instance(bx.cx, &instance);
+                    let llfn = callee::get_fn(bx.cx, instance);
+
+                    // Codegen the actual panic invoke/call.
+                    do_call(
+                        self,
+                        bx,
+                        fn_ty,
+                        llfn,
+                        &[msg_file_line_col],
+                        destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
+                        cleanup,
+                    );
+                    return;
+                }
+
                 let extra_args = &args[sig.inputs().len()..];
                 let extra_args = extra_args.iter().map(|op_arg| {
                     let op_ty = op_arg.ty(self.mir, bx.tcx());
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 5c4cd849f89..96eb6916322 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -802,6 +802,14 @@ impl Abi {
             _ => false,
         }
     }
+
+    /// Returns true if this is an uninhabited type
+    pub fn is_uninhabited(&self) -> bool {
+        match *self {
+            Abi::Uninhabited => true,
+            _ => false,
+        }
+    }
 }
 
 #[derive(PartialEq, Eq, Hash, Debug)]
diff --git a/src/test/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs
new file mode 100644
index 00000000000..a4115f8fa1d
--- /dev/null
+++ b/src/test/run-pass/panic-uninitialized-zeroed.rs
@@ -0,0 +1,31 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
+// in a runtime panic.
+
+#![feature(never_type)]
+
+use std::{mem, panic};
+
+struct Foo {
+    x: u8,
+    y: !,
+}
+
+fn main() {
+    unsafe {
+        panic::catch_unwind(|| mem::uninitialized::<!>()).is_err();
+        panic::catch_unwind(|| mem::zeroed::<!>()).is_err();
+
+        panic::catch_unwind(|| mem::uninitialized::<Foo>()).is_err();
+        panic::catch_unwind(|| mem::zeroed::<Foo>()).is_err();
+    }
+}