]> git.lizzy.rs Git - rust.git/commitdiff
panic when instantiating an uninhabited type via mem::{uninitialized,zeroed}
authorJorge Aparicio <jorge@japaric.io>
Sun, 19 Aug 2018 15:36:04 +0000 (17:36 +0200)
committerRalf Jung <post@ralfj.de>
Sun, 30 Sep 2018 15:26:15 +0000 (17:26 +0200)
src/librustc_codegen_llvm/mir/block.rs
src/librustc_target/abi/mod.rs
src/test/run-pass/panic-uninitialized-zeroed.rs [new file with mode: 0644]

index a534b4e478fb793e4f96496e4621287c25eb0a24..72fb9df6f81bdaca8821b89d5c452a08088aa05c 100644 (file)
@@ -463,6 +463,55 @@ fn codegen_terminator(&mut self,
                     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());
index 5c4cd849f89bcd681e323d5db483f2d6764a874e..96eb69163220e7b33c57287bd9ac35596ab6b589 100644 (file)
@@ -802,6 +802,14 @@ pub fn is_signed(&self) -> bool {
             _ => 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 (file)
index 0000000..a4115f8
--- /dev/null
@@ -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();
+    }
+}