diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index e756313a1253d..8bfe46568eb19 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -449,7 +449,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
                 }
             }
 
-            if sized && fields.iter().any(|f| f.abi == Abi::Uninhabited) {
+            if sized && fields.iter().any(|f| f.abi.is_uninhabited()) {
                 abi = Abi::Uninhabited;
             }
 
@@ -724,7 +724,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
                 // See issue #49298 for more details on the need to leave space
                 // for non-ZST uninhabited data (mostly partial initialization).
                 let absent = |fields: &[TyLayout<'_>]| {
-                    let uninhabited = fields.iter().any(|f| f.abi == Abi::Uninhabited);
+                    let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
                     let is_zst = fields.iter().all(|f| f.is_zst());
                     uninhabited && is_zst
                 };
@@ -872,7 +872,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
                                 _ => Abi::Aggregate { sized: true },
                             };
 
-                            if st.iter().all(|v| v.abi == Abi::Uninhabited) {
+                            if st.iter().all(|v| v.abi.is_uninhabited()) {
                                 abi = Abi::Uninhabited;
                             }
 
@@ -900,7 +900,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
                 let discr_type = def.repr.discr_type();
                 let bits = Integer::from_attr(tcx, discr_type).size().bits();
                 for (i, discr) in def.discriminants(tcx).enumerate() {
-                    if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) {
+                    if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
                         continue;
                     }
                     let mut x = discr.val as i128;
@@ -1096,7 +1096,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
                     }
                 }
 
-                if layout_variants.iter().all(|v| v.abi == Abi::Uninhabited) {
+                if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
                     abi = Abi::Uninhabited;
                 }
 
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index 99919a940b405..7b0c413e85761 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -279,7 +279,7 @@ pub fn create_function_debug_context(
         }
         None => {}
     };
-    if cx.layout_of(sig.output()).abi == ty::layout::Abi::Uninhabited {
+    if cx.layout_of(sig.output()).abi.is_uninhabited() {
         flags = flags | DIFlags::FlagNoReturn;
     }
 
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 5e743ac51bc61..7141c9ece89d7 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -23,7 +23,7 @@
 use llvm;
 use llvm::AttributePlace::Function;
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{self, LayoutOf};
+use rustc::ty::layout::LayoutOf;
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_target::spec::PanicStrategy;
@@ -137,7 +137,7 @@ pub fn declare_fn(
     let fty = FnType::new(cx, sig, &[]);
     let llfn = declare_raw_fn(cx, name, fty.llvm_cconv(), fty.llvm_type(cx));
 
-    if cx.layout_of(sig.output()).abi == layout::Abi::Uninhabited {
+    if cx.layout_of(sig.output()).abi.is_uninhabited() {
         llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
     }
 
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index a534b4e478fb7..709fceb492509 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -482,6 +482,54 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     _ => FnType::new(bx.cx, 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 = 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 = 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 = 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;
+                }
+
                 // The arguments we'll be passing. Plus one to account for outptr, if used.
                 let arg_count = fn_ty.args.len() + fn_ty.ret.is_indirect() as usize;
                 let mut llargs = Vec::with_capacity(arg_count);
diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs
index c781b456af6b2..e7b6f5908a4d1 100644
--- a/src/librustc_codegen_llvm/mir/place.rs
+++ b/src/librustc_codegen_llvm/mir/place.rs
@@ -275,7 +275,7 @@ impl PlaceRef<'ll, 'tcx> {
     /// Obtain the actual discriminant of a value.
     pub fn codegen_get_discr(self, bx: &Builder<'a, 'll, 'tcx>, cast_to: Ty<'tcx>) -> &'ll Value {
         let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx);
-        if self.layout.abi == layout::Abi::Uninhabited {
+        if self.layout.abi.is_uninhabited() {
             return C_undef(cast_to);
         }
         match self.layout.variants {
@@ -338,7 +338,7 @@ impl PlaceRef<'ll, 'tcx> {
     /// Set the discriminant for a new value of the given case of the given
     /// representation.
     pub fn codegen_set_discr(&self, bx: &Builder<'a, 'll, 'tcx>, variant_index: usize) {
-        if self.layout.for_variant(bx.cx, variant_index).abi == layout::Abi::Uninhabited {
+        if self.layout.for_variant(bx.cx, variant_index).abi.is_uninhabited() {
             return;
         }
         match self.layout.variants {
diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs
index c3ec347f60876..fa22bdff94ddd 100644
--- a/src/librustc_codegen_llvm/mir/rvalue.rs
+++ b/src/librustc_codegen_llvm/mir/rvalue.rs
@@ -290,7 +290,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     mir::CastKind::Misc => {
                         assert!(cast.is_llvm_immediate());
                         let ll_t_out = cast.immediate_llvm_type(bx.cx);
-                        if operand.layout.abi == layout::Abi::Uninhabited {
+                        if operand.layout.abi.is_uninhabited() {
                             return (bx, OperandRef {
                                 val: OperandValue::Immediate(C_undef(ll_t_out)),
                                 layout: cast,
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index fef2f916b4156..a11150c47836e 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -514,7 +514,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         rval: OpTy<'tcx>,
     ) -> EvalResult<'tcx, (u128, usize)> {
         trace!("read_discriminant_value {:#?}", rval.layout);
-        if rval.layout.abi == layout::Abi::Uninhabited {
+        if rval.layout.abi.is_uninhabited() {
             return err!(Unreachable);
         }
 
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 5c4cd849f89bc..96eb69163220e 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/codegen/box-maybe-uninit.rs b/src/test/codegen/box-maybe-uninit.rs
new file mode 100644
index 0000000000000..168e1a3eba0c5
--- /dev/null
+++ b/src/test/codegen/box-maybe-uninit.rs
@@ -0,0 +1,23 @@
+// Copyright 2017 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.
+
+// compile-flags: -O
+#![crate_type="lib"]
+#![feature(maybe_uninit)]
+
+use std::mem::MaybeUninit;
+
+// Boxing a `MaybeUninit` value should not copy junk from the stack
+#[no_mangle]
+pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
+    // CHECK-LABEL: @box_uninitialized
+    // CHECK-NOT: store
+    Box::new(MaybeUninit::uninitialized())
+}
diff --git a/src/test/debuginfo/nil-enum.rs b/src/test/debuginfo/nil-enum.rs
index 94377421c0b0c..ab9c7e2dd2758 100644
--- a/src/test/debuginfo/nil-enum.rs
+++ b/src/test/debuginfo/nil-enum.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// NOTE Instantiating an empty enum is UB. This test may break in the future.
+
 // LLDB can't handle zero-sized values
 // ignore-lldb
 
@@ -25,8 +27,11 @@
 
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
+#![feature(maybe_uninit)]
 #![omit_gdb_pretty_printer_section]
 
+use std::mem::MaybeUninit;
+
 enum ANilEnum {}
 enum AnotherNilEnum {}
 
@@ -35,8 +40,8 @@ enum AnotherNilEnum {}
 // The error from gdbr is expected since nil enums are not supposed to exist.
 fn main() {
     unsafe {
-        let first: ANilEnum = ::std::mem::zeroed();
-        let second: AnotherNilEnum = ::std::mem::zeroed();
+        let first: ANilEnum = MaybeUninit::uninitialized().into_inner();
+        let second: AnotherNilEnum = MaybeUninit::uninitialized().into_inner();
 
         zzz(); // #break
     }
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 0000000000000..2972f6efa32e0
--- /dev/null
+++ b/src/test/run-pass/panic-uninitialized-zeroed.rs
@@ -0,0 +1,83 @@
+// 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.
+
+// ignore-wasm32-bare always compiled as panic=abort right now and this requires unwinding
+// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
+// in a runtime panic.
+
+#![feature(never_type)]
+
+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 ! using mem::uninitialized"
+            })),
+            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 ! using mem::zeroed"
+            })),
+            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 using mem::uninitialized"
+            })),
+            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 using mem::zeroed"
+            })),
+            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 using mem::uninitialized"
+            })),
+            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 using mem::zeroed"
+            })),
+            Some(true)
+        );
+    }
+}