diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 3c060cc6e840b..265ed48809527 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1021,46 +1021,8 @@ extern "rust-intrinsic" {
     #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")]
     pub fn caller_location() -> &'static crate::panic::Location<'static>;
 
-    /// Creates a value initialized to zero.
-    ///
-    /// `init` is unsafe because it returns a zeroed-out datum,
-    /// which is unsafe unless `T` is `Copy`. Also, even if T is
-    /// `Copy`, an all-zero value may not correspond to any legitimate
-    /// state for the type in question.
-    ///
-    /// The stabilized version of this intrinsic is
-    /// [`std::mem::zeroed`](../../std/mem/fn.zeroed.html).
-    #[unstable(
-        feature = "core_intrinsics",
-        reason = "intrinsics are unlikely to ever be stabilized, instead \
-                         they should be used through stabilized interfaces \
-                         in the rest of the standard library",
-        issue = "none"
-    )]
-    #[rustc_deprecated(reason = "superseded by MaybeUninit, removal planned", since = "1.38.0")]
-    pub fn init<T>() -> T;
-
-    /// Creates an uninitialized value.
-    ///
-    /// `uninit` is unsafe because there is no guarantee of what its
-    /// contents are. In particular its drop-flag may be set to any
-    /// state, which means it may claim either dropped or
-    /// undropped. In the general case one must use `ptr::write` to
-    /// initialize memory previous set to the result of `uninit`.
-    ///
-    /// The stabilized version of this intrinsic is
-    /// [`std::mem::MaybeUninit`](../../std/mem/union.MaybeUninit.html).
-    #[unstable(
-        feature = "core_intrinsics",
-        reason = "intrinsics are unlikely to ever be stabilized, instead \
-                         they should be used through stabilized interfaces \
-                         in the rest of the standard library",
-        issue = "none"
-    )]
-    #[rustc_deprecated(reason = "superseded by MaybeUninit, removal planned", since = "1.38.0")]
-    pub fn uninit<T>() -> T;
-
     /// Moves a value out of scope without running drop glue.
+    /// This exists solely for `mem::forget_unsized`; normal `forget` uses `ManuallyDrop` instead.
     pub fn forget<T: ?Sized>(_: T);
 
     /// Reinterprets the bits of a value of one type as another type.
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index 7d9a8bcd05b1c..ae4c0a98ea930 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -490,7 +490,7 @@ pub const fn needs_drop<T>() -> bool {
 ///
 /// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior!
 /// ```
-#[inline]
+#[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated_in_future)]
 #[allow(deprecated)]
@@ -500,7 +500,7 @@ pub unsafe fn zeroed<T>() -> T {
     intrinsics::panic_if_zero_invalid::<T>();
     #[cfg(bootstrap)]
     intrinsics::panic_if_uninhabited::<T>();
-    intrinsics::init()
+    MaybeUninit::zeroed().assume_init()
 }
 
 /// Bypasses Rust's normal memory-initialization checks by pretending to
@@ -525,7 +525,7 @@ pub unsafe fn zeroed<T>() -> T {
 /// [uninit]: union.MaybeUninit.html#method.uninit
 /// [assume_init]: union.MaybeUninit.html#method.assume_init
 /// [inv]: union.MaybeUninit.html#initialization-invariant
-#[inline]
+#[inline(always)]
 #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated_in_future)]
@@ -536,7 +536,7 @@ pub unsafe fn uninitialized<T>() -> T {
     intrinsics::panic_if_any_invalid::<T>();
     #[cfg(bootstrap)]
     intrinsics::panic_if_uninhabited::<T>();
-    intrinsics::uninit()
+    MaybeUninit::uninit().assume_init()
 }
 
 /// Swaps the values at two mutable locations, without deinitializing either one.
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 1ae9d2a684131..aa42d557b0261 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -195,26 +195,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                     .unwrap();
                 OperandRef::from_const(self, ty_name, ret_ty).immediate_or_packed_pair(self)
             }
-            "init" => {
-                let ty = substs.type_at(0);
-                if !self.layout_of(ty).is_zst() {
-                    // Just zero out the stack slot.
-                    // If we store a zero constant, LLVM will drown in vreg allocation for large
-                    // data structures, and the generated code will be awful. (A telltale sign of
-                    // this is large quantities of `mov [byte ptr foo],0` in the generated code.)
-                    memset_intrinsic(
-                        self,
-                        false,
-                        ty,
-                        llresult,
-                        self.const_u8(0),
-                        self.const_usize(1),
-                    );
-                }
-                return;
-            }
-            // Effectively no-ops
-            "uninit" | "forget" => {
+            // Effectively no-op
+            "forget" => {
                 return;
             }
             "offset" => {
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index d2a358c3e09b8..36b7ef87b5ef4 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -150,8 +150,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             "panic_if_uninhabited" | "panic_if_zero_invalid" | "panic_if_any_invalid" => {
                 (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()),
             "transmute" => (2, vec![param(0)], param(1)),
             "move_val_init" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
diff --git a/src/test/ui/init-large-type.rs b/src/test/ui/init-large-type.rs
index a304fc9356b51..ce905572f2a8c 100644
--- a/src/test/ui/init-large-type.rs
+++ b/src/test/ui/init-large-type.rs
@@ -1,3 +1,4 @@
+// compile-flags: -O
 // run-pass
 
 #![allow(unused_must_use)]
@@ -10,17 +11,13 @@
 
 #![feature(intrinsics)]
 
-use std::thread;
-
-extern "rust-intrinsic" {
-    pub fn init<T>() -> T;
-}
+use std::{mem, thread};
 
 const SIZE: usize = 1024 * 1024;
 
 fn main() {
     // do the test in a new thread to avoid (spurious?) stack overflows
     thread::spawn(|| {
-        let _memory: [u8; SIZE] = unsafe { init() };
+        let _memory: [u8; SIZE] = unsafe { mem::zeroed() };
     }).join();
 }
diff --git a/src/test/ui/init-unsafe.rs b/src/test/ui/init-unsafe.rs
deleted file mode 100644
index 3d65cfc234092..0000000000000
--- a/src/test/ui/init-unsafe.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![allow(deprecated)]
-#![feature(core_intrinsics)]
-
-use std::intrinsics::{init};
-
-// Test that the `init` intrinsic is really unsafe
-pub fn main() {
-    let stuff = init::<isize>(); //~ ERROR call to unsafe function is unsafe
-}
diff --git a/src/test/ui/init-unsafe.stderr b/src/test/ui/init-unsafe.stderr
deleted file mode 100644
index e1126316af34e..0000000000000
--- a/src/test/ui/init-unsafe.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/init-unsafe.rs:8:17
-   |
-LL |     let stuff = init::<isize>();
-   |                 ^^^^^^^^^^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/intrinsics/intrinsic-move-val.rs b/src/test/ui/intrinsics/intrinsic-move-val.rs
index 75b4ec365fe03..b672f1ed26e8d 100644
--- a/src/test/ui/intrinsics/intrinsic-move-val.rs
+++ b/src/test/ui/intrinsics/intrinsic-move-val.rs
@@ -5,7 +5,6 @@
 
 mod rusti {
     extern "rust-intrinsic" {
-        pub fn init<T>() -> T;
         pub fn move_val_init<T>(dst: *mut T, src: T);
     }
 }
@@ -15,17 +14,17 @@ pub fn main() {
         // sanity check
         check_drops_state(0, None);
 
-        let mut x: Box<D> = box D(1);
-        assert_eq!(x.0, 1);
+        let mut x: Option<Box<D>> = Some(box D(1));
+        assert_eq!(x.as_ref().unwrap().0, 1);
 
         // A normal overwrite, to demonstrate `check_drops_state`.
-        x = box D(2);
+        x = Some(box D(2));
 
         // At this point, one destructor has run, because the
         // overwrite of `x` drops its initial value.
         check_drops_state(1, Some(1));
 
-        let mut y: Box<D> = rusti::init();
+        let mut y: Option<Box<D>> = std::mem::zeroed();
 
         // An initial binding does not overwrite anything.
         check_drops_state(1, Some(1));
@@ -51,9 +50,9 @@ pub fn main() {
         // during such a destructor call. We do so after the end of
         // this scope.
 
-        assert_eq!(y.0, 2);
-        y.0 = 3;
-        assert_eq!(y.0, 3);
+        assert_eq!(y.as_ref().unwrap().0, 2);
+        y.as_mut().unwrap().0 = 3;
+        assert_eq!(y.as_ref().unwrap().0, 3);
 
         check_drops_state(1, Some(1));
     }
diff --git a/src/test/ui/intrinsics/intrinsic-uninit.rs b/src/test/ui/intrinsics/intrinsic-uninit.rs
deleted file mode 100644
index 9555efb639b50..0000000000000
--- a/src/test/ui/intrinsics/intrinsic-uninit.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// run-pass
-// pretty-expanded FIXME #23616
-
-#![feature(intrinsics)]
-
-mod rusti {
-    extern "rust-intrinsic" {
-        pub fn uninit<T>() -> T;
-    }
-}
-pub fn main() {
-    let _a : isize = unsafe {rusti::uninit()};
-}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-unstable.rs b/src/test/ui/proc-macro/auxiliary/derive-unstable.rs
index f702df66db1b8..2ccd3f88200e3 100644
--- a/src/test/ui/proc-macro/auxiliary/derive-unstable.rs
+++ b/src/test/ui/proc-macro/auxiliary/derive-unstable.rs
@@ -10,5 +10,5 @@ use proc_macro::TokenStream;
 #[proc_macro_derive(Unstable)]
 pub fn derive(_input: TokenStream) -> TokenStream {
 
-    "unsafe fn foo() -> u32 { ::std::intrinsics::init() }".parse().unwrap()
+    "unsafe fn foo() -> u32 { ::std::intrinsics::abort() }".parse().unwrap()
 }