From a06edda3ad9abd4f07d07bbe46cb488efeebbbd0 Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@tavianator.com>
Date: Wed, 9 Sep 2020 10:16:03 -0400
Subject: [PATCH 01/21] Fix segfault if pthread_getattr_np fails

glibc destroys[1] the passed pthread_attr_t if pthread_getattr_np()
fails.  Destroying it again leads to a segfault.  Fix it by only
destroying it on success for glibc.

[1]: https://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_getattr_np.c;h=ce437205e41dc05653e435f6188768cccdd91c99;hb=HEAD#l205
---
 library/std/src/sys/unix/thread.rs | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 04da9812ddc45..569aedd741192 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -305,7 +305,9 @@ pub mod guard {
             assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
             ret = Some(stackaddr);
         }
-        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+        if e == 0 || cfg!(not(target_env = "gnu")) {
+            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+        }
         ret
     }
 
@@ -446,7 +448,9 @@ pub mod guard {
                 Some(stackaddr..stackaddr + guardsize)
             };
         }
-        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+        if e == 0 || cfg!(not(target_env = "gnu")) {
+            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+        }
         ret
     }
 }

From a684153f2920729f9fc3ea27ddb77d7cc3543214 Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@tavianator.com>
Date: Wed, 9 Sep 2020 11:10:43 -0400
Subject: [PATCH 02/21] Only call pthread_attr_destroy() after getattr_np()
 succeeds on all libcs

The calling convention of pthread_getattr_np() is to initialize the
pthread_attr_t, so _destroy() is only necessary on success (and _init()
isn't necessary beforehand).  On the other hand, FreeBSD wants the
attr_t to be initialized before pthread_attr_get_np(), and therefore it
should always be destroyed afterwards.
---
 library/std/src/sys/unix/thread.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 569aedd741192..652219e28f6e0 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -294,6 +294,7 @@ pub mod guard {
     unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
         let mut ret = None;
         let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
+        #[cfg(target_os = "freebsd")]
         assert_eq!(libc::pthread_attr_init(&mut attr), 0);
         #[cfg(target_os = "freebsd")]
         let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
@@ -305,7 +306,7 @@ pub mod guard {
             assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
             ret = Some(stackaddr);
         }
-        if e == 0 || cfg!(not(target_env = "gnu")) {
+        if e == 0 || cfg!(target_os = "freebsd") {
             assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
         }
         ret
@@ -405,6 +406,7 @@ pub mod guard {
     pub unsafe fn current() -> Option<Guard> {
         let mut ret = None;
         let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
+        #[cfg(target_os = "freebsd")]
         assert_eq!(libc::pthread_attr_init(&mut attr), 0);
         #[cfg(target_os = "freebsd")]
         let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
@@ -448,7 +450,7 @@ pub mod guard {
                 Some(stackaddr..stackaddr + guardsize)
             };
         }
-        if e == 0 || cfg!(not(target_env = "gnu")) {
+        if e == 0 || cfg!(target_os = "freebsd") {
             assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
         }
         ret

From 176956c115c2b797471a3f59eef3e17789229007 Mon Sep 17 00:00:00 2001
From: Stein Somers <git@steinsomers.be>
Date: Tue, 15 Sep 2020 00:02:48 +0200
Subject: [PATCH 03/21] Test and fix Sync & Send traits of BTreeMap artefacts

---
 library/alloc/src/collections/btree/borrow.rs |   3 +
 .../alloc/src/collections/btree/map/tests.rs  | 140 ++++++++++++++++++
 2 files changed, 143 insertions(+)

diff --git a/library/alloc/src/collections/btree/borrow.rs b/library/alloc/src/collections/btree/borrow.rs
index 5c95acfbe9c20..016f139a501a0 100644
--- a/library/alloc/src/collections/btree/borrow.rs
+++ b/library/alloc/src/collections/btree/borrow.rs
@@ -16,6 +16,9 @@ pub struct DormantMutRef<'a, T> {
     _marker: PhantomData<&'a mut T>,
 }
 
+unsafe impl<'a, T> Sync for DormantMutRef<'a, T> where &'a mut T: Sync {}
+unsafe impl<'a, T> Send for DormantMutRef<'a, T> where &'a mut T: Send {}
+
 impl<'a, T> DormantMutRef<'a, T> {
     /// Capture a unique borrow, and immediately reborrow it. For the compiler,
     /// the lifetime of the new reference is the same as the lifetime of the
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index af5cf7d7d875c..d2cd6b8e5241a 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -1418,6 +1418,146 @@ fn test_variance() {
     }
 }
 
+#[test]
+#[allow(dead_code)]
+fn test_sync() {
+    fn map<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+        v
+    }
+
+    fn into_iter<T: Sync>(v: BTreeMap<T, T>) -> impl Sync {
+        v.into_iter()
+    }
+
+    fn into_keys<T: Sync + Ord>(v: BTreeMap<T, T>) -> impl Sync {
+        v.into_keys()
+    }
+
+    fn into_values<T: Sync + Ord>(v: BTreeMap<T, T>) -> impl Sync {
+        v.into_values()
+    }
+
+    fn drain_filter<T: Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+        v.drain_filter(|_, _| false)
+    }
+
+    fn iter<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+        v.iter()
+    }
+
+    fn iter_mut<T: Sync>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+        v.iter_mut()
+    }
+
+    fn keys<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+        v.keys()
+    }
+
+    fn values<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+        v.values()
+    }
+
+    fn values_mut<T: Sync>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+        v.values_mut()
+    }
+
+    fn range<T: Sync + Ord>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
+        v.range(..)
+    }
+
+    fn range_mut<T: Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+        v.range_mut(..)
+    }
+
+    fn entry<T: Sync + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+        v.entry(Default::default())
+    }
+
+    fn occupied_entry<T: Sync + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+        match v.entry(Default::default()) {
+            Occupied(entry) => entry,
+            _ => unreachable!(),
+        }
+    }
+
+    fn vacant_entry<T: Sync + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
+        match v.entry(Default::default()) {
+            Vacant(entry) => entry,
+            _ => unreachable!(),
+        }
+    }
+}
+
+#[test]
+#[allow(dead_code)]
+fn test_send() {
+    fn map<T: Send>(v: BTreeMap<T, T>) -> impl Send {
+        v
+    }
+
+    fn into_iter<T: Send>(v: BTreeMap<T, T>) -> impl Send {
+        v.into_iter()
+    }
+
+    fn into_keys<T: Send + Ord>(v: BTreeMap<T, T>) -> impl Send {
+        v.into_keys()
+    }
+
+    fn into_values<T: Send + Ord>(v: BTreeMap<T, T>) -> impl Send {
+        v.into_values()
+    }
+
+    fn drain_filter<T: Send + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+        v.drain_filter(|_, _| false)
+    }
+
+    fn iter<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ {
+        v.iter()
+    }
+
+    fn iter_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+        v.iter_mut()
+    }
+
+    fn keys<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ {
+        v.keys()
+    }
+
+    fn values<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ {
+        v.values()
+    }
+
+    fn values_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+        v.values_mut()
+    }
+
+    fn range<T: Send + Sync + Ord>(v: &BTreeMap<T, T>) -> impl Send + '_ {
+        v.range(..)
+    }
+
+    fn range_mut<T: Send + Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+        v.range_mut(..)
+    }
+
+    fn entry<T: Send + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+        v.entry(Default::default())
+    }
+
+    fn occupied_entry<T: Send + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+        match v.entry(Default::default()) {
+            Occupied(entry) => entry,
+            _ => unreachable!(),
+        }
+    }
+
+    fn vacant_entry<T: Send + Ord + Default>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+        match v.entry(Default::default()) {
+            Vacant(entry) => entry,
+            _ => unreachable!(),
+        }
+    }
+}
+
 #[test]
 fn test_occupied_entry_key() {
     let mut a = BTreeMap::new();

From 21b0c1286a1f01cb8a21bda0973833ca11889364 Mon Sep 17 00:00:00 2001
From: khyperia <github@khyperia.com>
Date: Tue, 15 Sep 2020 23:35:31 +0200
Subject: [PATCH 04/21] Extract some intrinsics out of rustc_codegen_llvm

A significant amount of intrinsics do not actually need backend-specific
behaviors to be implemented, instead relying on methods already in
rustc_codegen_ssa. So, extract those methods out to rustc_codegen_ssa,
so that each backend doesn't need to reimplement the same code.
---
 compiler/rustc_codegen_llvm/src/intrinsic.rs  | 527 +---------------
 compiler/rustc_codegen_ssa/src/mir/block.rs   |   3 +-
 .../rustc_codegen_ssa/src/mir/intrinsic.rs    | 596 ++++++++++++++++++
 compiler/rustc_codegen_ssa/src/mir/mod.rs     |   1 +
 4 files changed, 606 insertions(+), 521 deletions(-)
 create mode 100644 compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 2208ceca00c83..7f5b09eac4f9e 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -7,15 +7,12 @@ use crate::type_of::LayoutLlvmExt;
 use crate::va_arg::emit_va_arg;
 use crate::value::Value;
 
-use rustc_ast as ast;
 use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
-use rustc_codegen_ssa::glue;
-use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
+use rustc_codegen_ssa::mir::operand::OperandRef;
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::*;
-use rustc_codegen_ssa::MemFlags;
 use rustc_hir as hir;
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
 use rustc_middle::ty::{self, Ty};
@@ -71,8 +68,6 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Va
         sym::nearbyintf64 => "llvm.nearbyint.f64",
         sym::roundf32 => "llvm.round.f32",
         sym::roundf64 => "llvm.round.f64",
-        sym::assume => "llvm.assume",
-        sym::abort => "llvm.trap",
         _ => return None,
     };
     Some(cx.get_intrinsic(&llvm_name))
@@ -112,9 +107,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
                 None,
             ),
-            sym::unreachable => {
-                return;
-            }
             sym::likely => {
                 let expect = self.get_intrinsic(&("llvm.expect.i1"));
                 self.call(expect, &[args[0].immediate(), self.const_bool(true)], None)
@@ -137,8 +129,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 let llfn = self.get_intrinsic(&("llvm.debugtrap"));
                 self.call(llfn, &[], None)
             }
-            sym::va_start => self.va_start(args[0].immediate()),
-            sym::va_end => self.va_end(args[0].immediate()),
             sym::va_copy => {
                 let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy"));
                 self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None)
@@ -169,123 +159,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                     _ => bug!("the va_arg intrinsic does not work with non-scalar types"),
                 }
             }
-            sym::size_of_val => {
-                let tp_ty = substs.type_at(0);
-                if let OperandValue::Pair(_, meta) = args[0].val {
-                    let (llsize, _) = glue::size_and_align_of_dst(self, tp_ty, Some(meta));
-                    llsize
-                } else {
-                    self.const_usize(self.size_of(tp_ty).bytes())
-                }
-            }
-            sym::min_align_of_val => {
-                let tp_ty = substs.type_at(0);
-                if let OperandValue::Pair(_, meta) = args[0].val {
-                    let (_, llalign) = glue::size_and_align_of_dst(self, tp_ty, Some(meta));
-                    llalign
-                } else {
-                    self.const_usize(self.align_of(tp_ty).bytes())
-                }
-            }
-            sym::size_of
-            | sym::pref_align_of
-            | sym::min_align_of
-            | sym::needs_drop
-            | sym::type_id
-            | sym::type_name
-            | sym::variant_count => {
-                let value = self
-                    .tcx
-                    .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
-                    .unwrap();
-                OperandRef::from_const(self, value, ret_ty).immediate_or_packed_pair(self)
-            }
-            // Effectively no-op
-            sym::forget => {
-                return;
-            }
-            sym::offset => {
-                let ptr = args[0].immediate();
-                let offset = args[1].immediate();
-                self.inbounds_gep(ptr, &[offset])
-            }
-            sym::arith_offset => {
-                let ptr = args[0].immediate();
-                let offset = args[1].immediate();
-                self.gep(ptr, &[offset])
-            }
-
-            sym::copy_nonoverlapping => {
-                copy_intrinsic(
-                    self,
-                    false,
-                    false,
-                    substs.type_at(0),
-                    args[1].immediate(),
-                    args[0].immediate(),
-                    args[2].immediate(),
-                );
-                return;
-            }
-            sym::copy => {
-                copy_intrinsic(
-                    self,
-                    true,
-                    false,
-                    substs.type_at(0),
-                    args[1].immediate(),
-                    args[0].immediate(),
-                    args[2].immediate(),
-                );
-                return;
-            }
-            sym::write_bytes => {
-                memset_intrinsic(
-                    self,
-                    false,
-                    substs.type_at(0),
-                    args[0].immediate(),
-                    args[1].immediate(),
-                    args[2].immediate(),
-                );
-                return;
-            }
 
-            sym::volatile_copy_nonoverlapping_memory => {
-                copy_intrinsic(
-                    self,
-                    false,
-                    true,
-                    substs.type_at(0),
-                    args[0].immediate(),
-                    args[1].immediate(),
-                    args[2].immediate(),
-                );
-                return;
-            }
-            sym::volatile_copy_memory => {
-                copy_intrinsic(
-                    self,
-                    true,
-                    true,
-                    substs.type_at(0),
-                    args[0].immediate(),
-                    args[1].immediate(),
-                    args[2].immediate(),
-                );
-                return;
-            }
-            sym::volatile_set_memory => {
-                memset_intrinsic(
-                    self,
-                    true,
-                    substs.type_at(0),
-                    args[0].immediate(),
-                    args[1].immediate(),
-                    args[2].immediate(),
-                );
-                return;
-            }
             sym::volatile_load | sym::unaligned_volatile_load => {
                 let tp_ty = substs.type_at(0);
                 let mut ptr = args[0].immediate();
@@ -343,20 +217,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
             | sym::ctpop
             | sym::bswap
             | sym::bitreverse
-            | sym::add_with_overflow
-            | sym::sub_with_overflow
-            | sym::mul_with_overflow
-            | sym::wrapping_add
-            | sym::wrapping_sub
-            | sym::wrapping_mul
-            | sym::unchecked_div
-            | sym::unchecked_rem
-            | sym::unchecked_shl
-            | sym::unchecked_shr
-            | sym::unchecked_add
-            | sym::unchecked_sub
-            | sym::unchecked_mul
-            | sym::exact_div
             | sym::rotate_left
             | sym::rotate_right
             | sym::saturating_add
@@ -396,84 +256,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                             &[args[0].immediate()],
                             None,
                         ),
-                        sym::add_with_overflow
-                        | sym::sub_with_overflow
-                        | sym::mul_with_overflow => {
-                            let intrinsic = format!(
-                                "llvm.{}{}.with.overflow.i{}",
-                                if signed { 's' } else { 'u' },
-                                &name_str[..3],
-                                width
-                            );
-                            let llfn = self.get_intrinsic(&intrinsic);
-
-                            // Convert `i1` to a `bool`, and write it to the out parameter
-                            let pair =
-                                self.call(llfn, &[args[0].immediate(), args[1].immediate()], None);
-                            let val = self.extract_value(pair, 0);
-                            let overflow = self.extract_value(pair, 1);
-                            let overflow = self.zext(overflow, self.type_bool());
-
-                            let dest = result.project_field(self, 0);
-                            self.store(val, dest.llval, dest.align);
-                            let dest = result.project_field(self, 1);
-                            self.store(overflow, dest.llval, dest.align);
-
-                            return;
-                        }
-                        sym::wrapping_add => self.add(args[0].immediate(), args[1].immediate()),
-                        sym::wrapping_sub => self.sub(args[0].immediate(), args[1].immediate()),
-                        sym::wrapping_mul => self.mul(args[0].immediate(), args[1].immediate()),
-                        sym::exact_div => {
-                            if signed {
-                                self.exactsdiv(args[0].immediate(), args[1].immediate())
-                            } else {
-                                self.exactudiv(args[0].immediate(), args[1].immediate())
-                            }
-                        }
-                        sym::unchecked_div => {
-                            if signed {
-                                self.sdiv(args[0].immediate(), args[1].immediate())
-                            } else {
-                                self.udiv(args[0].immediate(), args[1].immediate())
-                            }
-                        }
-                        sym::unchecked_rem => {
-                            if signed {
-                                self.srem(args[0].immediate(), args[1].immediate())
-                            } else {
-                                self.urem(args[0].immediate(), args[1].immediate())
-                            }
-                        }
-                        sym::unchecked_shl => self.shl(args[0].immediate(), args[1].immediate()),
-                        sym::unchecked_shr => {
-                            if signed {
-                                self.ashr(args[0].immediate(), args[1].immediate())
-                            } else {
-                                self.lshr(args[0].immediate(), args[1].immediate())
-                            }
-                        }
-                        sym::unchecked_add => {
-                            if signed {
-                                self.unchecked_sadd(args[0].immediate(), args[1].immediate())
-                            } else {
-                                self.unchecked_uadd(args[0].immediate(), args[1].immediate())
-                            }
-                        }
-                        sym::unchecked_sub => {
-                            if signed {
-                                self.unchecked_ssub(args[0].immediate(), args[1].immediate())
-                            } else {
-                                self.unchecked_usub(args[0].immediate(), args[1].immediate())
-                            }
-                        }
-                        sym::unchecked_mul => {
-                            if signed {
-                                self.unchecked_smul(args[0].immediate(), args[1].immediate())
-                            } else {
-                                self.unchecked_umul(args[0].immediate(), args[1].immediate())
-                            }
-                        }
                         sym::rotate_left | sym::rotate_right => {
                             let is_left = name == sym::rotate_left;
                             let val = args[0].immediate();
@@ -513,75 +295,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                     }
                 }
             }
-            sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
-                match float_type_width(arg_tys[0]) {
-                    Some(_width) => match name {
-                        sym::fadd_fast => self.fadd_fast(args[0].immediate(), args[1].immediate()),
-                        sym::fsub_fast => self.fsub_fast(args[0].immediate(), args[1].immediate()),
-                        sym::fmul_fast => self.fmul_fast(args[0].immediate(), args[1].immediate()),
-                        sym::fdiv_fast => self.fdiv_fast(args[0].immediate(), args[1].immediate()),
-                        sym::frem_fast => self.frem_fast(args[0].immediate(), args[1].immediate()),
-                        _ => bug!(),
-                    },
-                    None => {
-                        span_invalid_monomorphization_error(
-                            tcx.sess,
-                            span,
-                            &format!(
-                                "invalid monomorphization of `{}` intrinsic: \
-                                      expected basic float type, found `{}`",
-                                name, arg_tys[0]
-                            ),
-                        );
-                        return;
-                    }
-                }
-            }
-
-            sym::float_to_int_unchecked => {
-                if float_type_width(arg_tys[0]).is_none() {
-                    span_invalid_monomorphization_error(
-                        tcx.sess,
-                        span,
-                        &format!(
-                            "invalid monomorphization of `float_to_int_unchecked` \
-                                  intrinsic: expected basic float type, \
-                                  found `{}`",
-                            arg_tys[0]
-                        ),
-                    );
-                    return;
-                }
-                let (width, signed) = match int_type_width_signed(ret_ty, self.cx) {
-                    Some(pair) => pair,
-                    None => {
-                        span_invalid_monomorphization_error(
-                            tcx.sess,
-                            span,
-                            &format!(
-                                "invalid monomorphization of `float_to_int_unchecked` \
-                                      intrinsic:  expected basic integer type, \
-                                      found `{}`",
-                                ret_ty
-                            ),
-                        );
-                        return;
-                    }
-                };
-                if signed {
-                    self.fptosi(args[0].immediate(), self.cx.type_ix(width))
-                } else {
-                    self.fptoui(args[0].immediate(), self.cx.type_ix(width))
-                }
-            }
-
-            sym::discriminant_value => {
-                if ret_ty.is_integral() {
-                    args[0].deref(self.cx()).codegen_get_discr(self, ret_ty)
-                } else {
-                    span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0])
-                }
-            }
 
             _ if name_str.starts_with("simd_") => {
                 match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
@@ -589,174 +302,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                     Err(()) => return,
                 }
             }
-            // This requires that atomic intrinsics follow a specific naming pattern:
-            // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
-            name if name_str.starts_with("atomic_") => {
-                use rustc_codegen_ssa::common::AtomicOrdering::*;
-                use rustc_codegen_ssa::common::{AtomicRmwBinOp, SynchronizationScope};
-
-                let split: Vec<&str> = name_str.split('_').collect();
-
-                let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak";
-                let (order, failorder) = match split.len() {
-                    2 => (SequentiallyConsistent, SequentiallyConsistent),
-                    3 => match split[2] {
-                        "unordered" => (Unordered, Unordered),
-                        "relaxed" => (Monotonic, Monotonic),
-                        "acq" => (Acquire, Acquire),
-                        "rel" => (Release, Monotonic),
-                        "acqrel" => (AcquireRelease, Acquire),
-                        "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic),
-                        "failacq" if is_cxchg => (SequentiallyConsistent, Acquire),
-                        _ => self.sess().fatal("unknown ordering in atomic intrinsic"),
-                    },
-                    4 => match (split[2], split[3]) {
-                        ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic),
-                        ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic),
-                        _ => self.sess().fatal("unknown ordering in atomic intrinsic"),
-                    },
-                    _ => self.sess().fatal("Atomic intrinsic not in correct format"),
-                };
-
-                let invalid_monomorphization = |ty| {
-                    span_invalid_monomorphization_error(
-                        tcx.sess,
-                        span,
-                        &format!(
-                            "invalid monomorphization of `{}` intrinsic: \
-                                  expected basic integer type, found `{}`",
-                            name, ty
-                        ),
-                    );
-                };
-
-                match split[1] {
-                    "cxchg" | "cxchgweak" => {
-                        let ty = substs.type_at(0);
-                        if int_type_width_signed(ty, self).is_some() {
-                            let weak = split[1] == "cxchgweak";
-                            let pair = self.atomic_cmpxchg(
-                                args[0].immediate(),
-                                args[1].immediate(),
-                                args[2].immediate(),
-                                order,
-                                failorder,
-                                weak,
-                            );
-                            let val = self.extract_value(pair, 0);
-                            let success = self.extract_value(pair, 1);
-                            let success = self.zext(success, self.type_bool());
-
-                            let dest = result.project_field(self, 0);
-                            self.store(val, dest.llval, dest.align);
-                            let dest = result.project_field(self, 1);
-                            self.store(success, dest.llval, dest.align);
-                            return;
-                        } else {
-                            return invalid_monomorphization(ty);
-                        }
-                    }
-
-                    "load" => {
-                        let ty = substs.type_at(0);
-                        if int_type_width_signed(ty, self).is_some() {
-                            let size = self.size_of(ty);
-                            self.atomic_load(args[0].immediate(), order, size)
-                        } else {
-                            return invalid_monomorphization(ty);
-                        }
-                    }
-
-                    "store" => {
-                        let ty = substs.type_at(0);
-                        if int_type_width_signed(ty, self).is_some() {
-                            let size = self.size_of(ty);
-                            self.atomic_store(
-                                args[1].immediate(),
-                                args[0].immediate(),
-                                order,
-                                size,
-                            );
-                            return;
-                        } else {
-                            return invalid_monomorphization(ty);
-                        }
-                    }
-
-                    "fence" => {
-                        self.atomic_fence(order, SynchronizationScope::CrossThread);
-                        return;
-                    }
-
-                    "singlethreadfence" => {
-                        self.atomic_fence(order, SynchronizationScope::SingleThread);
-                        return;
-                    }
-
-                    // These are all AtomicRMW ops
-                    op => {
-                        let atom_op = match op {
-                            "xchg" => AtomicRmwBinOp::AtomicXchg,
-                            "xadd" => AtomicRmwBinOp::AtomicAdd,
-                            "xsub" => AtomicRmwBinOp::AtomicSub,
-                            "and" => AtomicRmwBinOp::AtomicAnd,
-                            "nand" => AtomicRmwBinOp::AtomicNand,
-                            "or" => AtomicRmwBinOp::AtomicOr,
-                            "xor" => AtomicRmwBinOp::AtomicXor,
-                            "max" => AtomicRmwBinOp::AtomicMax,
-                            "min" => AtomicRmwBinOp::AtomicMin,
-                            "umax" => AtomicRmwBinOp::AtomicUMax,
-                            "umin" => AtomicRmwBinOp::AtomicUMin,
-                            _ => self.sess().fatal("unknown atomic operation"),
-                        };
-
-                        let ty = substs.type_at(0);
-                        if int_type_width_signed(ty, self).is_some() {
-                            self.atomic_rmw(
-                                atom_op,
-                                args[0].immediate(),
-                                args[1].immediate(),
-                                order,
-                            )
-                        } else {
-                            return invalid_monomorphization(ty);
-                        }
-                    }
-                }
-            }
-
-            sym::nontemporal_store => {
-                let dst = args[0].deref(self.cx());
-                args[1].val.nontemporal_store(self, dst);
-                return;
-            }
-
-            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
-                let a = args[0].immediate();
-                let b = args[1].immediate();
-                if name == sym::ptr_guaranteed_eq {
-                    self.icmp(IntPredicate::IntEQ, a, b)
-                } else {
-                    self.icmp(IntPredicate::IntNE, a, b)
-                }
-            }
-
-            sym::ptr_offset_from => {
-                let ty = substs.type_at(0);
-                let pointee_size = self.size_of(ty);
-
-                // This is the same sequence that Clang emits for pointer subtraction.
-                // It can be neither `nsw` nor `nuw` because the input is treated as
-                // unsigned but then the output is treated as signed, so neither works.
-                let a = args[0].immediate();
-                let b = args[1].immediate();
-                let a = self.ptrtoint(a, self.type_isize());
-                let b = self.ptrtoint(b, self.type_isize());
-                let d = self.sub(a, b);
-                let pointee_size = self.const_usize(pointee_size.bytes());
-                // this is where the signed magic happens (notice the `s` in `exactsdiv`)
-                self.exactsdiv(d, pointee_size)
-            }
 
             _ => bug!("unknown intrinsic '{}'", name),
         };
@@ -807,39 +352,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     }
 }
 
-fn copy_intrinsic(
-    bx: &mut Builder<'a, 'll, 'tcx>,
-    allow_overlap: bool,
-    volatile: bool,
-    ty: Ty<'tcx>,
-    dst: &'ll Value,
-    src: &'ll Value,
-    count: &'ll Value,
-) {
-    let (size, align) = bx.size_and_align_of(ty);
-    let size = bx.mul(bx.const_usize(size.bytes()), count);
-    let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
-    if allow_overlap {
-        bx.memmove(dst, align, src, align, size, flags);
-    } else {
-        bx.memcpy(dst, align, src, align, size, flags);
-    }
-}
-
-fn memset_intrinsic(
-    bx: &mut Builder<'a, 'll, 'tcx>,
-    volatile: bool,
-    ty: Ty<'tcx>,
-    dst: &'ll Value,
-    val: &'ll Value,
-    count: &'ll Value,
-) {
-    let (size, align) = bx.size_and_align_of(ty);
-    let size = bx.mul(bx.const_usize(size.bytes()), count);
-    let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
-    bx.memset(dst, val, size, align, flags);
-}
-
 fn try_intrinsic(
     bx: &mut Builder<'a, 'll, 'tcx>,
     try_func: &'ll Value,
@@ -2205,37 +1717,12 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
 // stuffs.
 fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> {
     match ty.kind() {
-        ty::Int(t) => Some((
-            match t {
-                ast::IntTy::Isize => u64::from(cx.tcx.sess.target.ptr_width),
-                ast::IntTy::I8 => 8,
-                ast::IntTy::I16 => 16,
-                ast::IntTy::I32 => 32,
-                ast::IntTy::I64 => 64,
-                ast::IntTy::I128 => 128,
-            },
-            true,
-        )),
-        ty::Uint(t) => Some((
-            match t {
-                ast::UintTy::Usize => u64::from(cx.tcx.sess.target.ptr_width),
-                ast::UintTy::U8 => 8,
-                ast::UintTy::U16 => 16,
-                ast::UintTy::U32 => 32,
-                ast::UintTy::U64 => 64,
-                ast::UintTy::U128 => 128,
-            },
-            false,
-        )),
-        _ => None,
-    }
-}
-
-// Returns the width of a float Ty
-// Returns None if the type is not a float
-fn float_type_width(ty: Ty<'_>) -> Option<u64> {
-    match ty.kind() {
-        ty::Float(t) => Some(t.bit_width()),
+        ty::Int(t) => {
+            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true))
+        }
+        ty::Uint(t) => {
+            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false))
+        }
         _ => None,
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 4639ce4a5ab5b..4f85d232caa68 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -687,7 +687,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 })
                 .collect();
 
-            bx.codegen_intrinsic_call(
+            Self::codegen_intrinsic_call(
+                &mut bx,
                 *instance.as_ref().unwrap(),
                 &fn_abi,
                 &args,
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
new file mode 100644
index 0000000000000..14f1ed59a67c5
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -0,0 +1,596 @@
+use super::operand::{OperandRef, OperandValue};
+use super::place::PlaceRef;
+use super::FunctionCx;
+use crate::common::{span_invalid_monomorphization_error, IntPredicate};
+use crate::glue;
+use crate::traits::*;
+use crate::MemFlags;
+
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::{sym, Span};
+use rustc_target::abi::call::{FnAbi, PassMode};
+
+fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &mut Bx,
+    allow_overlap: bool,
+    volatile: bool,
+    ty: Ty<'tcx>,
+    dst: Bx::Value,
+    src: Bx::Value,
+    count: Bx::Value,
+) {
+    let layout = bx.layout_of(ty);
+    let size = layout.size;
+    let align = layout.align.abi;
+    let size = bx.mul(bx.const_usize(size.bytes()), count);
+    let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
+    if allow_overlap {
+        bx.memmove(dst, align, src, align, size, flags);
+    } else {
+        bx.memcpy(dst, align, src, align, size, flags);
+    }
+}
+
+fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &mut Bx,
+    volatile: bool,
+    ty: Ty<'tcx>,
+    dst: Bx::Value,
+    val: Bx::Value,
+    count: Bx::Value,
+) {
+    let layout = bx.layout_of(ty);
+    let size = layout.size;
+    let align = layout.align.abi;
+    let size = bx.mul(bx.const_usize(size.bytes()), count);
+    let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
+    bx.memset(dst, val, size, align, flags);
+}
+
+impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
+    pub fn codegen_intrinsic_call(
+        bx: &mut Bx,
+        instance: ty::Instance<'tcx>,
+        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+        args: &[OperandRef<'tcx, Bx::Value>],
+        llresult: Bx::Value,
+        span: Span,
+    ) {
+        let callee_ty = instance.ty(bx.tcx(), ty::ParamEnv::reveal_all());
+
+        let (def_id, substs) = match *callee_ty.kind() {
+            ty::FnDef(def_id, substs) => (def_id, substs),
+            _ => bug!("expected fn item type, found {}", callee_ty),
+        };
+
+        let sig = callee_ty.fn_sig(bx.tcx());
+        let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+        let arg_tys = sig.inputs();
+        let ret_ty = sig.output();
+        let name = bx.tcx().item_name(def_id);
+        let name_str = &*name.as_str();
+
+        let llret_ty = bx.backend_type(bx.layout_of(ret_ty));
+        let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
+
+        let llval = match name {
+            sym::assume => {
+                bx.assume(args[0].immediate());
+                return;
+            }
+            sym::abort => {
+                bx.abort();
+                return;
+            }
+
+            sym::unreachable => {
+                return;
+            }
+            sym::va_start => bx.va_start(args[0].immediate()),
+            sym::va_end => bx.va_end(args[0].immediate()),
+            sym::size_of_val => {
+                let tp_ty = substs.type_at(0);
+                if let OperandValue::Pair(_, meta) = args[0].val {
+                    let (llsize, _) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
+                    llsize
+                } else {
+                    bx.const_usize(bx.layout_of(tp_ty).size.bytes())
+                }
+            }
+            sym::min_align_of_val => {
+                let tp_ty = substs.type_at(0);
+                if let OperandValue::Pair(_, meta) = args[0].val {
+                    let (_, llalign) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
+                    llalign
+                } else {
+                    bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes())
+                }
+            }
+            sym::size_of
+            | sym::pref_align_of
+            | sym::min_align_of
+            | sym::needs_drop
+            | sym::type_id
+            | sym::type_name
+            | sym::variant_count => {
+                let value = bx
+                    .tcx()
+                    .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
+                    .unwrap();
+                OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx)
+            }
+            // Effectively no-op
+            sym::forget => {
+                return;
+            }
+            sym::offset => {
+                let ptr = args[0].immediate();
+                let offset = args[1].immediate();
+                bx.inbounds_gep(ptr, &[offset])
+            }
+            sym::arith_offset => {
+                let ptr = args[0].immediate();
+                let offset = args[1].immediate();
+                bx.gep(ptr, &[offset])
+            }
+
+            sym::copy_nonoverlapping => {
+                copy_intrinsic(
+                    bx,
+                    false,
+                    false,
+                    substs.type_at(0),
+                    args[1].immediate(),
+                    args[0].immediate(),
+                    args[2].immediate(),
+                );
+                return;
+            }
+            sym::copy => {
+                copy_intrinsic(
+                    bx,
+                    true,
+                    false,
+                    substs.type_at(0),
+                    args[1].immediate(),
+                    args[0].immediate(),
+                    args[2].immediate(),
+                );
+                return;
+            }
+            sym::write_bytes => {
+                memset_intrinsic(
+                    bx,
+                    false,
+                    substs.type_at(0),
+                    args[0].immediate(),
+                    args[1].immediate(),
+                    args[2].immediate(),
+                );
+                return;
+            }
+
+            sym::volatile_copy_nonoverlapping_memory => {
+                copy_intrinsic(
+                    bx,
+                    false,
+                    true,
+                    substs.type_at(0),
+                    args[0].immediate(),
+                    args[1].immediate(),
+                    args[2].immediate(),
+                );
+                return;
+            }
+            sym::volatile_copy_memory => {
+                copy_intrinsic(
+                    bx,
+                    true,
+                    true,
+                    substs.type_at(0),
+                    args[0].immediate(),
+                    args[1].immediate(),
+                    args[2].immediate(),
+                );
+                return;
+            }
+            sym::volatile_set_memory => {
+                memset_intrinsic(
+                    bx,
+                    true,
+                    substs.type_at(0),
+                    args[0].immediate(),
+                    args[1].immediate(),
+                    args[2].immediate(),
+                );
+                return;
+            }
+            sym::volatile_store => {
+                let dst = args[0].deref(bx.cx());
+                args[1].val.volatile_store(bx, dst);
+                return;
+            }
+            sym::unaligned_volatile_store => {
+                let dst = args[0].deref(bx.cx());
+                args[1].val.unaligned_volatile_store(bx, dst);
+                return;
+            }
+            sym::add_with_overflow
+            | sym::sub_with_overflow
+            | sym::mul_with_overflow
+            | sym::wrapping_add
+            | sym::wrapping_sub
+            | sym::wrapping_mul
+            | sym::unchecked_div
+            | sym::unchecked_rem
+            | sym::unchecked_shl
+            | sym::unchecked_shr
+            | sym::unchecked_add
+            | sym::unchecked_sub
+            | sym::unchecked_mul
+            | sym::exact_div => {
+                let ty = arg_tys[0];
+                match int_type_width_signed(ty, bx.tcx()) {
+                    Some((_width, signed)) => match name {
+                        sym::add_with_overflow
+                        | sym::sub_with_overflow
+                        | sym::mul_with_overflow => {
+                            let op = match name {
+                                sym::add_with_overflow => OverflowOp::Add,
+                                sym::sub_with_overflow => OverflowOp::Sub,
+                                sym::mul_with_overflow => OverflowOp::Mul,
+                                _ => bug!(),
+                            };
+                            let (val, overflow) =
+                                bx.checked_binop(op, ty, args[0].immediate(), args[1].immediate());
+                            // Convert `i1` to a `bool`, and write it to the out parameter
+                            let val = bx.from_immediate(val);
+                            let overflow = bx.from_immediate(overflow);
+
+                            let dest = result.project_field(bx, 0);
+                            bx.store(val, dest.llval, dest.align);
+                            let dest = result.project_field(bx, 1);
+                            bx.store(overflow, dest.llval, dest.align);
+
+                            return;
+                        }
+                        sym::wrapping_add => bx.add(args[0].immediate(), args[1].immediate()),
+                        sym::wrapping_sub => bx.sub(args[0].immediate(), args[1].immediate()),
+                        sym::wrapping_mul => bx.mul(args[0].immediate(), args[1].immediate()),
+                        sym::exact_div => {
+                            if signed {
+                                bx.exactsdiv(args[0].immediate(), args[1].immediate())
+                            } else {
+                                bx.exactudiv(args[0].immediate(), args[1].immediate())
+                            }
+                        }
+                        sym::unchecked_div => {
+                            if signed {
+                                bx.sdiv(args[0].immediate(), args[1].immediate())
+                            } else {
+                                bx.udiv(args[0].immediate(), args[1].immediate())
+                            }
+                        }
+                        sym::unchecked_rem => {
+                            if signed {
+                                bx.srem(args[0].immediate(), args[1].immediate())
+                            } else {
+                                bx.urem(args[0].immediate(), args[1].immediate())
+                            }
+                        }
+                        sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()),
+                        sym::unchecked_shr => {
+                            if signed {
+                                bx.ashr(args[0].immediate(), args[1].immediate())
+                            } else {
+                                bx.lshr(args[0].immediate(), args[1].immediate())
+                            }
+                        }
+                        sym::unchecked_add => {
+                            if signed {
+                                bx.unchecked_sadd(args[0].immediate(), args[1].immediate())
+                            } else {
+                                bx.unchecked_uadd(args[0].immediate(), args[1].immediate())
+                            }
+                        }
+                        sym::unchecked_sub => {
+                            if signed {
+                                bx.unchecked_ssub(args[0].immediate(), args[1].immediate())
+                            } else {
+                                bx.unchecked_usub(args[0].immediate(), args[1].immediate())
+                            }
+                        }
+                        sym::unchecked_mul => {
+                            if signed {
+                                bx.unchecked_smul(args[0].immediate(), args[1].immediate())
+                            } else {
+                                bx.unchecked_umul(args[0].immediate(), args[1].immediate())
+                            }
+                        }
+                        _ => bug!(),
+                    },
+                    None => {
+                        span_invalid_monomorphization_error(
+                            bx.tcx().sess,
+                            span,
+                            &format!(
+                                "invalid monomorphization of `{}` intrinsic: \
+                                      expected basic integer type, found `{}`",
+                                name, ty
+                            ),
+                        );
+                        return;
+                    }
+                }
+            }
+            sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
+                match float_type_width(arg_tys[0]) {
+                    Some(_width) => match name {
+                        sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()),
+                        sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()),
+                        sym::fmul_fast => bx.fmul_fast(args[0].immediate(), args[1].immediate()),
+                        sym::fdiv_fast => bx.fdiv_fast(args[0].immediate(), args[1].immediate()),
+                        sym::frem_fast => bx.frem_fast(args[0].immediate(), args[1].immediate()),
+                        _ => bug!(),
+                    },
+                    None => {
+                        span_invalid_monomorphization_error(
+                            bx.tcx().sess,
+                            span,
+                            &format!(
+                                "invalid monomorphization of `{}` intrinsic: \
+                                      expected basic float type, found `{}`",
+                                name, arg_tys[0]
+                            ),
+                        );
+                        return;
+                    }
+                }
+            }
+
+            sym::float_to_int_unchecked => {
+                if float_type_width(arg_tys[0]).is_none() {
+                    span_invalid_monomorphization_error(
+                        bx.tcx().sess,
+                        span,
+                        &format!(
+                            "invalid monomorphization of `float_to_int_unchecked` \
+                                  intrinsic: expected basic float type, \
+                                  found `{}`",
+                            arg_tys[0]
+                        ),
+                    );
+                    return;
+                }
+                let (_width, signed) = match int_type_width_signed(ret_ty, bx.tcx()) {
+                    Some(pair) => pair,
+                    None => {
+                        span_invalid_monomorphization_error(
+                            bx.tcx().sess,
+                            span,
+                            &format!(
+                                "invalid monomorphization of `float_to_int_unchecked` \
+                                      intrinsic:  expected basic integer type, \
+                                      found `{}`",
+                                ret_ty
+                            ),
+                        );
+                        return;
+                    }
+                };
+                if signed {
+                    bx.fptosi(args[0].immediate(), llret_ty)
+                } else {
+                    bx.fptoui(args[0].immediate(), llret_ty)
+                }
+            }
+
+            sym::discriminant_value => {
+                if ret_ty.is_integral() {
+                    args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty)
+                } else {
+                    span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0])
+                }
+            }
+
+            // This requires that atomic intrinsics follow a specific naming pattern:
+            // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
+            name if name_str.starts_with("atomic_") => {
+                use crate::common::AtomicOrdering::*;
+                use crate::common::{AtomicRmwBinOp, SynchronizationScope};
+
+                let split: Vec<&str> = name_str.split('_').collect();
+
+                let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak";
+                let (order, failorder) = match split.len() {
+                    2 => (SequentiallyConsistent, SequentiallyConsistent),
+                    3 => match split[2] {
+                        "unordered" => (Unordered, Unordered),
+                        "relaxed" => (Monotonic, Monotonic),
+                        "acq" => (Acquire, Acquire),
+                        "rel" => (Release, Monotonic),
+                        "acqrel" => (AcquireRelease, Acquire),
+                        "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic),
+                        "failacq" if is_cxchg => (SequentiallyConsistent, Acquire),
+                        _ => bx.sess().fatal("unknown ordering in atomic intrinsic"),
+                    },
+                    4 => match (split[2], split[3]) {
+                        ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic),
+                        ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic),
+                        _ => bx.sess().fatal("unknown ordering in atomic intrinsic"),
+                    },
+                    _ => bx.sess().fatal("Atomic intrinsic not in correct format"),
+                };
+
+                let invalid_monomorphization = |ty| {
+                    span_invalid_monomorphization_error(
+                        bx.tcx().sess,
+                        span,
+                        &format!(
+                            "invalid monomorphization of `{}` intrinsic: \
+                                  expected basic integer type, found `{}`",
+                            name, ty
+                        ),
+                    );
+                };
+
+                match split[1] {
+                    "cxchg" | "cxchgweak" => {
+                        let ty = substs.type_at(0);
+                        if int_type_width_signed(ty, bx.tcx()).is_some() {
+                            let weak = split[1] == "cxchgweak";
+                            let pair = bx.atomic_cmpxchg(
+                                args[0].immediate(),
+                                args[1].immediate(),
+                                args[2].immediate(),
+                                order,
+                                failorder,
+                                weak,
+                            );
+                            let val = bx.extract_value(pair, 0);
+                            let success = bx.extract_value(pair, 1);
+                            let val = bx.from_immediate(val);
+                            let success = bx.from_immediate(success);
+
+                            let dest = result.project_field(bx, 0);
+                            bx.store(val, dest.llval, dest.align);
+                            let dest = result.project_field(bx, 1);
+                            bx.store(success, dest.llval, dest.align);
+                            return;
+                        } else {
+                            return invalid_monomorphization(ty);
+                        }
+                    }
+
+                    "load" => {
+                        let ty = substs.type_at(0);
+                        if int_type_width_signed(ty, bx.tcx()).is_some() {
+                            let size = bx.layout_of(ty).size;
+                            bx.atomic_load(args[0].immediate(), order, size)
+                        } else {
+                            return invalid_monomorphization(ty);
+                        }
+                    }
+
+                    "store" => {
+                        let ty = substs.type_at(0);
+                        if int_type_width_signed(ty, bx.tcx()).is_some() {
+                            let size = bx.layout_of(ty).size;
+                            bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size);
+                            return;
+                        } else {
+                            return invalid_monomorphization(ty);
+                        }
+                    }
+
+                    "fence" => {
+                        bx.atomic_fence(order, SynchronizationScope::CrossThread);
+                        return;
+                    }
+
+                    "singlethreadfence" => {
+                        bx.atomic_fence(order, SynchronizationScope::SingleThread);
+                        return;
+                    }
+
+                    // These are all AtomicRMW ops
+                    op => {
+                        let atom_op = match op {
+                            "xchg" => AtomicRmwBinOp::AtomicXchg,
+                            "xadd" => AtomicRmwBinOp::AtomicAdd,
+                            "xsub" => AtomicRmwBinOp::AtomicSub,
+                            "and" => AtomicRmwBinOp::AtomicAnd,
+                            "nand" => AtomicRmwBinOp::AtomicNand,
+                            "or" => AtomicRmwBinOp::AtomicOr,
+                            "xor" => AtomicRmwBinOp::AtomicXor,
+                            "max" => AtomicRmwBinOp::AtomicMax,
+                            "min" => AtomicRmwBinOp::AtomicMin,
+                            "umax" => AtomicRmwBinOp::AtomicUMax,
+                            "umin" => AtomicRmwBinOp::AtomicUMin,
+                            _ => bx.sess().fatal("unknown atomic operation"),
+                        };
+
+                        let ty = substs.type_at(0);
+                        if int_type_width_signed(ty, bx.tcx()).is_some() {
+                            bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order)
+                        } else {
+                            return invalid_monomorphization(ty);
+                        }
+                    }
+                }
+            }
+
+            sym::nontemporal_store => {
+                let dst = args[0].deref(bx.cx());
+                args[1].val.nontemporal_store(bx, dst);
+                return;
+            }
+
+            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
+                let a = args[0].immediate();
+                let b = args[1].immediate();
+                if name == sym::ptr_guaranteed_eq {
+                    bx.icmp(IntPredicate::IntEQ, a, b)
+                } else {
+                    bx.icmp(IntPredicate::IntNE, a, b)
+                }
+            }
+
+            sym::ptr_offset_from => {
+                let ty = substs.type_at(0);
+                let pointee_size = bx.layout_of(ty).size;
+
+                // This is the same sequence that Clang emits for pointer subtraction.
+                // It can be neither `nsw` nor `nuw` because the input is treated as
+                // unsigned but then the output is treated as signed, so neither works.
+                let a = args[0].immediate();
+                let b = args[1].immediate();
+                let a = bx.ptrtoint(a, bx.type_isize());
+                let b = bx.ptrtoint(b, bx.type_isize());
+                let d = bx.sub(a, b);
+                let pointee_size = bx.const_usize(pointee_size.bytes());
+                // this is where the signed magic happens (notice the `s` in `exactsdiv`)
+                bx.exactsdiv(d, pointee_size)
+            }
+
+            _ => {
+                // Need to use backend-specific things in the implementation.
+                bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span);
+                return;
+            }
+        };
+
+        if !fn_abi.ret.is_ignore() {
+            if let PassMode::Cast(ty) = fn_abi.ret.mode {
+                let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(&ty));
+                let ptr = bx.pointercast(result.llval, ptr_llty);
+                bx.store(llval, ptr, result.align);
+            } else {
+                OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
+                    .val
+                    .store(bx, result);
+            }
+        }
+    }
+}
+
+// Returns the width of an int Ty, and if it's signed or not
+// Returns None if the type is not an integer
+// FIXME: there’s multiple of this functions, investigate using some of the already existing
+// stuffs.
+fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> {
+    match ty.kind() {
+        ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)),
+        ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)),
+        _ => None,
+    }
+}
+
+// Returns the width of a float Ty
+// Returns None if the type is not a float
+fn float_type_width(ty: Ty<'_>) -> Option<u64> {
+    match ty.kind() {
+        ty::Float(t) => Some(t.bit_width()),
+        _ => None,
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index c1e7cfd80ef10..64d456fb7aa67 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -486,6 +486,7 @@ mod block;
 pub mod constant;
 pub mod coverageinfo;
 pub mod debuginfo;
+mod intrinsic;
 pub mod operand;
 pub mod place;
 mod rvalue;

From eede953c283c7bbe903a0e8abb44c923baf5cfac Mon Sep 17 00:00:00 2001
From: Lzu Tao <taolzu@gmail.com>
Date: Thu, 10 Sep 2020 03:10:36 +0000
Subject: [PATCH 05/21] Only get ImplKind::Impl once

---
 src/librustdoc/clean/inline.rs | 41 ++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index f8987c6beca33..931355b82f503 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -350,14 +350,22 @@ pub fn build_impl(
         }
     }
 
-    let for_ = if let Some(did) = did.as_local() {
-        let hir_id = tcx.hir().local_def_id_to_hir_id(did);
-        match tcx.hir().expect_item(hir_id).kind {
-            hir::ItemKind::Impl { self_ty, .. } => self_ty.clean(cx),
-            _ => panic!("did given to build_impl was not an impl"),
+    let impl_item = match did.as_local() {
+        Some(did) => {
+            let hir_id = tcx.hir().local_def_id_to_hir_id(did);
+            match tcx.hir().expect_item(hir_id).kind {
+                hir::ItemKind::Impl { self_ty, ref generics, ref items, .. } => {
+                    Some((self_ty, generics, items))
+                }
+                _ => panic!("`DefID` passed to `build_impl` is not an `impl"),
+            }
         }
-    } else {
-        tcx.type_of(did).clean(cx)
+        None => None,
+    };
+
+    let for_ = match impl_item {
+        Some((self_ty, _, _)) => self_ty.clean(cx),
+        None => tcx.type_of(did).clean(cx),
     };
 
     // Only inline impl if the implementing type is
@@ -377,17 +385,12 @@ pub fn build_impl(
     }
 
     let predicates = tcx.explicit_predicates_of(did);
-    let (trait_items, generics) = if let Some(did) = did.as_local() {
-        let hir_id = tcx.hir().local_def_id_to_hir_id(did);
-        match tcx.hir().expect_item(hir_id).kind {
-            hir::ItemKind::Impl { ref generics, ref items, .. } => (
-                items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::<Vec<_>>(),
-                generics.clean(cx),
-            ),
-            _ => panic!("did given to build_impl was not an impl"),
-        }
-    } else {
-        (
+    let (trait_items, generics) = match impl_item {
+        Some((_, generics, items)) => (
+            items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::<Vec<_>>(),
+            generics.clean(cx),
+        ),
+        None => (
             tcx.associated_items(did)
                 .in_definition_order()
                 .filter_map(|item| {
@@ -399,7 +402,7 @@ pub fn build_impl(
                 })
                 .collect::<Vec<_>>(),
             clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)),
-        )
+        ),
     };
     let polarity = tcx.impl_polarity(did);
     let trait_ = associated_trait.clean(cx).map(|bound| match bound {

From c35ce3ff170333d11ccf89e75dc87c49f44a570a Mon Sep 17 00:00:00 2001
From: Joshua Nelson <jyn514@gmail.com>
Date: Wed, 16 Sep 2020 13:31:20 -0400
Subject: [PATCH 06/21] Don't generate bootstrap usage unless it's needed

Previously, `x.py` would unconditionally run `x.py build` to get the
help message. After https://github.com/rust-lang/rust/issues/76165,
when checking the CI stage was moved into `Config`, that would cause an
assertion failure (but only only in CI!):

```
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `1`,
 right: `2`', src/bootstrap/config.rs:619:49
```

This changes bootstrap to only generate a help message when it needs
to (when someone passes `--help`).
---
 src/bootstrap/flags.rs | 62 ++++++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 30 deletions(-)

diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index ff8468574469e..842c84a3e5cd6 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -98,7 +98,6 @@ impl Default for Subcommand {
 
 impl Flags {
     pub fn parse(args: &[String]) -> Flags {
-        let mut extra_help = String::new();
         let mut subcommand_help = String::from(
             "\
 Usage: x.py <subcommand> [options] [<paths>...]
@@ -170,16 +169,6 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
             "VALUE",
         );
 
-        // fn usage()
-        let usage =
-            |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
-                println!("{}", opts.usage(subcommand_help));
-                if !extra_help.is_empty() {
-                    println!("{}", extra_help);
-                }
-                process::exit(exit_code);
-            };
-
         // We can't use getopt to parse the options until we have completed specifying which
         // options are valid, but under the current implementation, some options are conditional on
         // the subcommand. Therefore we must manually identify the subcommand first, so that we can
@@ -263,12 +252,38 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
             _ => {}
         };
 
+        // fn usage()
+        let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
+            let mut extra_help = String::new();
+
+            // All subcommands except `clean` can have an optional "Available paths" section
+            if verbose {
+                let config = Config::parse(&["build".to_string()]);
+                let build = Build::new(config);
+
+                let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
+                extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
+            } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") {
+                extra_help.push_str(
+                    format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand)
+                        .as_str(),
+                );
+            }
+
+            println!("{}", opts.usage(subcommand_help));
+            if !extra_help.is_empty() {
+                println!("{}", extra_help);
+            }
+            process::exit(exit_code);
+        };
+
         // Done specifying what options are possible, so do the getopts parsing
         let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
             // Invalid argument/option format
             println!("\n{}\n", e);
-            usage(1, &opts, &subcommand_help, &extra_help);
+            usage(1, &opts, false, &subcommand_help);
         });
+
         // Extra sanity check to make sure we didn't hit this crazy corner case:
         //
         //     ./x.py --frobulate clean build
@@ -436,24 +451,11 @@ Arguments:
         let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
 
         let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
-
-        // All subcommands except `clean` can have an optional "Available paths" section
-        if matches.opt_present("verbose") {
-            let config = Config::parse(&["build".to_string()]);
-            let build = Build::new(config);
-
-            let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
-            extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
-        } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") {
-            extra_help.push_str(
-                format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand)
-                    .as_str(),
-            );
-        }
+        let verbose = matches.opt_present("verbose");
 
         // User passed in -h/--help?
         if matches.opt_present("help") {
-            usage(0, &opts, &subcommand_help, &extra_help);
+            usage(0, &opts, verbose, &subcommand_help);
         }
 
         let cmd = match subcommand.as_str() {
@@ -483,7 +485,7 @@ Arguments:
             "clean" => {
                 if !paths.is_empty() {
                     println!("\nclean does not take a path argument\n");
-                    usage(1, &opts, &subcommand_help, &extra_help);
+                    usage(1, &opts, verbose, &subcommand_help);
                 }
 
                 Subcommand::Clean { all: matches.opt_present("all") }
@@ -494,12 +496,12 @@ Arguments:
             "run" | "r" => {
                 if paths.is_empty() {
                     println!("\nrun requires at least a path!\n");
-                    usage(1, &opts, &subcommand_help, &extra_help);
+                    usage(1, &opts, verbose, &subcommand_help);
                 }
                 Subcommand::Run { paths }
             }
             _ => {
-                usage(1, &opts, &subcommand_help, &extra_help);
+                usage(1, &opts, verbose, &subcommand_help);
             }
         };
 

From 94dae6004035c356b00dac8764c1b4808d740928 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= <matthias.krueger@famsik.de>
Date: Wed, 16 Sep 2020 23:09:57 +0200
Subject: [PATCH 07/21] simplfy condition in ItemLowerer::with_trait_impl_ref()

---
 compiler/rustc_ast_lowering/src/item.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 6d41b7836b121..617cacee0e7f1 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -27,7 +27,7 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
 impl ItemLowerer<'_, '_, '_> {
     fn with_trait_impl_ref(&mut self, impl_ref: &Option<TraitRef>, f: impl FnOnce(&mut Self)) {
         let old = self.lctx.is_in_trait_impl;
-        self.lctx.is_in_trait_impl = if let &None = impl_ref { false } else { true };
+        self.lctx.is_in_trait_impl = impl_ref.is_some();
         f(self);
         self.lctx.is_in_trait_impl = old;
     }

From b7c8bea6cbf0aff4cbb36b127edc0bb4c66c4cf9 Mon Sep 17 00:00:00 2001
From: Ivan Tham <pickfire@riseup.net>
Date: Thu, 17 Sep 2020 09:07:19 +0800
Subject: [PATCH 08/21] Fix wording in mir doc

---
 compiler/rustc_middle/src/mir/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 29daf7e9309aa..467d0192a8144 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2285,7 +2285,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 /// Constants
 ///
 /// Two constants are equal if they are the same constant. Note that
-/// this does not necessarily mean that they are `==` in Rust -- in
+/// this does not necessarily mean that they are `==` in Rust. In
 /// particular, one must be wary of `NaN`!
 
 #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)]

From f4a7149f499a4b91d296678002f0bce4ded85038 Mon Sep 17 00:00:00 2001
From: Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
Date: Thu, 17 Sep 2020 10:56:08 +0800
Subject: [PATCH 09/21] Don't compile regex at every function call.

Use `SyncOnceCell` to only compile it once.
I believe this still adds some kind of locking mechanism?
---
 compiler/rustc_mir/src/dataflow/framework/graphviz.rs | 10 +++++++++-
 compiler/rustc_mir/src/lib.rs                         |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs
index 94151fbd0903a..5d4c4251961d2 100644
--- a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs
@@ -1,6 +1,7 @@
 //! A helpful diagram for debugging dataflow problems.
 
 use std::borrow::Cow;
+use std::lazy::SyncOnceCell;
 use std::{io, ops, str};
 
 use regex::Regex;
@@ -570,6 +571,13 @@ where
     }
 }
 
+macro_rules! regex {
+    ($re:literal $(,)?) => {{
+        static RE: SyncOnceCell<regex::Regex> = SyncOnceCell::new();
+        RE.get_or_init(|| Regex::new($re).unwrap())
+    }};
+}
+
 fn diff_pretty<T, C>(new: T, old: T, ctxt: &C) -> String
 where
     T: DebugWithContext<C>,
@@ -578,7 +586,7 @@ where
         return String::new();
     }
 
-    let re = Regex::new("\t?\u{001f}([+-])").unwrap();
+    let re = regex!("\t?\u{001f}([+-])");
 
     let raw_diff = format!("{:#?}", DebugDiffWithAdapter { new, old, ctxt });
 
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index 42717f273843a..8d2253b4d826b 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -27,6 +27,7 @@ Rust MIR: a lowered representation of Rust.
 #![feature(trait_alias)]
 #![feature(option_expect_none)]
 #![feature(or_patterns)]
+#![feature(once_cell)]
 #![recursion_limit = "256"]
 
 #[macro_use]

From b47913962097874257ad10227b943ef7af85d49f Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Thu, 17 Sep 2020 06:12:40 +0200
Subject: [PATCH 10/21] Remove intrinsics::arith_offset use from libarena

The use of arith_offset was added in 803e9ae67b770d8500c4ab5862e988d29118356a
before the stable wrapper of the intrinsic was available.

https://doc.rust-lang.org/stable/std/intrinsics/fn.arith_offset.html
---
 compiler/rustc_arena/src/lib.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 5e6a0340d12a0..16f735f055f92 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -11,7 +11,6 @@
     html_root_url = "https://doc.rust-lang.org/nightly/",
     test(no_crate_inject, attr(deny(warnings)))
 )]
-#![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(raw_vec_internals)]
 #![cfg_attr(test, feature(test))]
@@ -25,7 +24,6 @@ use smallvec::SmallVec;
 use std::alloc::Layout;
 use std::cell::{Cell, RefCell};
 use std::cmp;
-use std::intrinsics;
 use std::marker::{PhantomData, Send};
 use std::mem;
 use std::ptr;
@@ -130,7 +128,7 @@ impl<T> TypedArena<T> {
 
         unsafe {
             if mem::size_of::<T>() == 0 {
-                self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T);
+                self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T);
                 let ptr = mem::align_of::<T>() as *mut T;
                 // Don't drop the object. This `write` is equivalent to `forget`.
                 ptr::write(ptr, object);

From 4fe6ca37898bcd65488764f2679e27c936879ade Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Thu, 17 Sep 2020 07:08:34 +0200
Subject: [PATCH 11/21] Replace const_generics feature gate with
 min_const_generics

The latter is on the path to stabilization.
---
 compiler/rustc_data_structures/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 88c160e93b66a..b339261189b9c 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -26,7 +26,7 @@
 #![feature(thread_id_value)]
 #![feature(extend_one)]
 #![feature(const_panic)]
-#![feature(const_generics)]
+#![feature(min_const_generics)]
 #![feature(once_cell)]
 #![allow(rustc::default_hash_types)]
 

From ebdea011436dfea810ff1bbd827636ac75f6f092 Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Thu, 17 Sep 2020 07:46:35 +0200
Subject: [PATCH 12/21] Remove redundant #![feature(...)] 's from compiler/

---
 compiler/rustc_ast/src/lib.rs             | 4 ----
 compiler/rustc_codegen_ssa/src/lib.rs     | 2 --
 compiler/rustc_data_structures/src/lib.rs | 1 -
 compiler/rustc_expand/src/lib.rs          | 1 -
 compiler/rustc_infer/src/lib.rs           | 2 --
 compiler/rustc_middle/src/lib.rs          | 5 -----
 compiler/rustc_mir/src/lib.rs             | 3 ---
 compiler/rustc_parse/src/lib.rs           | 1 -
 compiler/rustc_parse_format/src/lib.rs    | 2 --
 compiler/rustc_privacy/src/lib.rs         | 1 -
 compiler/rustc_span/src/lib.rs            | 2 --
 compiler/rustc_traits/src/lib.rs          | 1 -
 compiler/rustc_ty/src/lib.rs              | 1 -
 13 files changed, 26 deletions(-)

diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index b556c1a446b7b..76b84d9da8334 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -5,17 +5,13 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
-#![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(const_fn)] // For the `transmute` in `P::new`
 #![feature(const_panic)]
-#![feature(const_fn_transmute)]
 #![feature(crate_visibility_modifier)]
 #![feature(label_break_value)]
 #![feature(nll)]
 #![feature(or_patterns)]
-#![feature(try_trait)]
-#![feature(unicode_internals)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 73e3336917587..a87ce1446ba14 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -8,8 +8,6 @@
 #![feature(or_patterns)]
 #![feature(trusted_len)]
 #![feature(associated_type_bounds)]
-#![feature(const_fn)] // for rustc_index::newtype_index
-#![feature(const_panic)] // for rustc_index::newtype_index
 #![recursion_limit = "256"]
 
 //! This crate contains codegen code that is used by all codegen backends (LLVM and others).
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index b339261189b9c..e5dd7107ff3ad 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -11,7 +11,6 @@
 #![feature(control_flow_enum)]
 #![feature(in_band_lifetimes)]
 #![feature(unboxed_closures)]
-#![feature(generators)]
 #![feature(generator_trait)]
 #![feature(fn_traits)]
 #![feature(min_specialization)]
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 5436b1ef737f5..47247294f5dc6 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(bool_to_option)]
-#![feature(cow_is_borrowed)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(or_patterns)]
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index e05041d88460e..504b66bae7329 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -13,7 +13,6 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![feature(bindings_after_at)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
@@ -23,7 +22,6 @@
 #![feature(never_type)]
 #![feature(or_patterns)]
 #![feature(in_band_lifetimes)]
-#![feature(crate_visibility_modifier)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index a675aae5b17d4..6b411ef8f09ee 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -30,12 +30,9 @@
 #![feature(cmp_min_max_by)]
 #![feature(const_fn)]
 #![feature(const_panic)]
-#![feature(const_fn_transmute)]
 #![feature(core_intrinsics)]
 #![feature(discriminant_kind)]
-#![feature(drain_filter)]
 #![feature(never_type)]
-#![feature(exhaustive_patterns)]
 #![feature(extern_types)]
 #![feature(nll)]
 #![feature(once_cell)]
@@ -43,13 +40,11 @@
 #![feature(or_patterns)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
-#![feature(stmt_expr_attributes)]
 #![feature(test)]
 #![feature(in_band_lifetimes)]
 #![feature(crate_visibility_modifier)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
-#![feature(hash_raw_entry)]
 #![feature(int_error_matching)]
 #![recursion_limit = "512"]
 
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index 42717f273843a..fae4a261b3e32 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -13,15 +13,12 @@ Rust MIR: a lowered representation of Rust.
 #![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
-#![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
 #![feature(exhaustive_patterns)]
-#![feature(iter_order_by)]
 #![feature(never_type)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
 #![feature(try_blocks)]
-#![feature(associated_type_bounds)]
 #![feature(associated_type_defaults)]
 #![feature(stmt_expr_attributes)]
 #![feature(trait_alias)]
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 0becdf24c532b..72a34b86ae20b 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -3,7 +3,6 @@
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(bindings_after_at)]
-#![feature(try_blocks)]
 #![feature(or_patterns)]
 
 use rustc_ast as ast;
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index e07b8b86aef8e..dde162681b773 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -11,8 +11,6 @@
 )]
 #![feature(nll)]
 #![feature(or_patterns)]
-#![feature(rustc_private)]
-#![feature(unicode_internals)]
 #![feature(bool_to_option)]
 
 pub use Alignment::*;
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 03cc718b8995d..d451a383b12a3 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,7 +1,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
-#![feature(or_patterns)]
 #![recursion_limit = "256"]
 
 use rustc_attr as attr;
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index e38cd516b91ac..1d1013967b7db 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -10,10 +10,8 @@
 #![feature(const_panic)]
 #![feature(negative_impls)]
 #![feature(nll)]
-#![feature(optin_builtin_traits)]
 #![feature(min_specialization)]
 #![feature(option_expect_none)]
-#![feature(refcell_take)]
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 6fea4732dda3f..d0b05beb4e63c 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -4,7 +4,6 @@
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
-#![feature(or_patterns)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_ty/src/lib.rs b/compiler/rustc_ty/src/lib.rs
index 6e9042d1ba7c8..8dd6aa3c7fcc1 100644
--- a/compiler/rustc_ty/src/lib.rs
+++ b/compiler/rustc_ty/src/lib.rs
@@ -5,7 +5,6 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![feature(bool_to_option)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 

From 5f58e00ca565c8964dbf89f510236f72951d0bab Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Thu, 17 Sep 2020 09:53:19 +0200
Subject: [PATCH 13/21] fix array_windows docs

---
 library/core/src/slice/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 8e9d1eb98a86b..9e716c487c169 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1034,7 +1034,7 @@ impl<T> [T] {
     ///
     /// This is the const generic equivalent of [`windows`].
     ///
-    /// If `N` is smaller than the size of the array, it will return no windows.
+    /// If `N` is greater than the size of the array, it will return no windows.
     ///
     /// # Panics
     ///

From 012974da7ad3737b296af4a401dfed2e8dcc22df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= <matthias.krueger@famsik.de>
Date: Thu, 17 Sep 2020 10:13:16 +0200
Subject: [PATCH 14/21] use strip_prefix over starts_with and manual slicing
 based on pattern length (clippy::manual_strip)

---
 compiler/rustc_driver/src/args.rs             |  3 +--
 .../borrow_check/diagnostics/move_errors.rs   |  4 ++--
 .../diagnostics/mutability_errors.rs          |  5 ++---
 .../rustc_resolve/src/late/diagnostics.rs     |  4 ++--
 compiler/rustc_session/src/search_paths.rs    | 20 +++++++++----------
 compiler/rustc_typeck/src/check/demand.rs     |  6 +++++-
 compiler/rustc_typeck/src/check/op.rs         |  8 ++++----
 compiler/rustc_typeck/src/collect.rs          |  4 ++--
 8 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/compiler/rustc_driver/src/args.rs b/compiler/rustc_driver/src/args.rs
index 5686819c61b40..4f2febf04b135 100644
--- a/compiler/rustc_driver/src/args.rs
+++ b/compiler/rustc_driver/src/args.rs
@@ -4,8 +4,7 @@ use std::fs;
 use std::io;
 
 pub fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
-    if arg.starts_with('@') {
-        let path = &arg[1..];
+    if let Some(path) = arg.strip_prefix('@') {
         let file = match fs::read_to_string(path) {
             Ok(file) => file,
             Err(ref err) if err.kind() == io::ErrorKind::InvalidData => {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
index e256fb55b124b..629e9be9ddd45 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
@@ -492,8 +492,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             {
                 if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
                 {
-                    if pat_snippet.starts_with('&') {
-                        let pat_snippet = pat_snippet[1..].trim_start();
+                    if let Some(stripped) = pat_snippet.strip_prefix('&') {
+                        let pat_snippet = stripped.trim_start();
                         let (suggestion, to_remove) = if pat_snippet.starts_with("mut")
                             && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
                         {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index 8b0121cf360e0..d4cdf02104ace 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -631,9 +631,8 @@ fn suggest_ampmut<'tcx>(
                 let lt_name = &src[1..ws_pos];
                 let ty = &src[ws_pos..];
                 return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
-            } else if src.starts_with('&') {
-                let borrowed_expr = &src[1..];
-                return (assignment_rhs_span, format!("&mut {}", borrowed_expr));
+            } else if let Some(stripped) = src.strip_prefix('&') {
+                return (assignment_rhs_span, format!("&mut {}", stripped));
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 2cc87dc637566..ced272e474d11 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1418,9 +1418,9 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                         if snippet.starts_with('&') && !snippet.starts_with("&'") {
                             introduce_suggestion
                                 .push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
-                        } else if snippet.starts_with("&'_ ") {
+                        } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
                             introduce_suggestion
-                                .push((param.span, format!("&{} {}", lt_name, &snippet[4..])));
+                                .push((param.span, format!("&{} {}", lt_name, stripped)));
                         }
                     }
                 }
diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs
index e12364b7dac7c..83b737a73b1e8 100644
--- a/compiler/rustc_session/src/search_paths.rs
+++ b/compiler/rustc_session/src/search_paths.rs
@@ -56,16 +56,16 @@ impl PathKind {
 
 impl SearchPath {
     pub fn from_cli_opt(path: &str, output: config::ErrorOutputType) -> Self {
-        let (kind, path) = if path.starts_with("native=") {
-            (PathKind::Native, &path["native=".len()..])
-        } else if path.starts_with("crate=") {
-            (PathKind::Crate, &path["crate=".len()..])
-        } else if path.starts_with("dependency=") {
-            (PathKind::Dependency, &path["dependency=".len()..])
-        } else if path.starts_with("framework=") {
-            (PathKind::Framework, &path["framework=".len()..])
-        } else if path.starts_with("all=") {
-            (PathKind::All, &path["all=".len()..])
+        let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") {
+            (PathKind::Native, stripped)
+        } else if let Some(stripped) = path.strip_prefix("crate=") {
+            (PathKind::Crate, stripped)
+        } else if let Some(stripped) = path.strip_prefix("dependency=") {
+            (PathKind::Dependency, stripped)
+        } else if let Some(stripped) = path.strip_prefix("framework=") {
+            (PathKind::Framework, stripped)
+        } else if let Some(stripped) = path.strip_prefix("all=") {
+            (PathKind::All, stripped)
         } else {
             (PathKind::All, path)
         };
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index f6b768bb12220..c7ce5008c3354 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -370,7 +370,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     {
         let s = s.as_ref();
         let old = old.as_ref();
-        if s.starts_with(old) { Some(new.as_ref().to_owned() + &s[old.len()..]) } else { None }
+        if let Some(stripped) = s.strip_prefix(old) {
+            Some(new.as_ref().to_owned() + stripped)
+        } else {
+            None
+        }
     }
 
     /// This function is used to determine potential "simple" improvements or users' errors and
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 529b8525a4a8d..66975f32a1f4a 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -589,10 +589,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 } else {
                                     msg
                                 },
-                                if lstring.starts_with('&') {
+                                if let Some(stripped) = lstring.strip_prefix('&') {
                                     // let a = String::new();
                                     // let _ = &a + "bar";
-                                    lstring[1..].to_string()
+                                    stripped.to_string()
                                 } else {
                                     format!("{}.to_owned()", lstring)
                                 },
@@ -617,10 +617,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     is_assign,
                 ) {
                     (Ok(l), Ok(r), IsAssign::No) => {
-                        let to_string = if l.starts_with('&') {
+                        let to_string = if let Some(stripped) = l.strip_prefix('&') {
                             // let a = String::new(); let b = String::new();
                             // let _ = &a + b;
-                            l[1..].to_string()
+                            stripped.to_string()
                         } else {
                             format!("{}.to_owned()", l)
                         };
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 9b8427a46955c..504b5a330f00c 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2341,8 +2341,8 @@ fn from_target_feature(
                         item.span(),
                         format!("`{}` is not valid for this target", feature),
                     );
-                    if feature.starts_with('+') {
-                        let valid = supported_target_features.contains_key(&feature[1..]);
+                    if let Some(stripped) = feature.strip_prefix('+') {
+                        let valid = supported_target_features.contains_key(stripped);
                         if valid {
                             err.help("consider removing the leading `+` in the feature name");
                         }

From 764d307963db8c50a47a9828a4c2eeea74d54007 Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Thu, 17 Sep 2020 10:30:28 +0200
Subject: [PATCH 15/21] docs `array`  -> `slice`

Co-authored-by: est31 <est31@users.noreply.github.com>
---
 library/core/src/slice/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 9e716c487c169..a3a1715b75e31 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1034,7 +1034,7 @@ impl<T> [T] {
     ///
     /// This is the const generic equivalent of [`windows`].
     ///
-    /// If `N` is greater than the size of the array, it will return no windows.
+    /// If `N` is greater than the size of the slice, it will return no windows.
     ///
     /// # Panics
     ///

From 1dd3df6738b5bbe676b6ae5b561c491ca483f017 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 17 Sep 2020 08:59:30 +0200
Subject: [PATCH 16/21] black_box: silence unused_mut warning when building
 with cfg(miri)

---
 library/core/src/hint.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 1192b9e164a14..fdf5bbf61441f 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -110,7 +110,7 @@ pub fn spin_loop() {
 /// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
 #[inline]
 #[unstable(feature = "test", issue = "50297")]
-#[allow(unreachable_code)] // this makes #[cfg] a bit easier below.
+#[cfg_attr(miri, allow(unused_mut))]
 pub fn black_box<T>(mut dummy: T) -> T {
     // We need to "use" the argument in some way LLVM can't introspect, and on
     // targets that support it we can typically leverage inline assembly to do

From 76ec3f8d2b9b1ae547652762d8ab5909eaa5793d Mon Sep 17 00:00:00 2001
From: Alexis Bourget <alexis.bourget@gmail.com>
Date: Thu, 17 Sep 2020 17:25:06 +0200
Subject: [PATCH 17/21] Move to intra doc links in core/src/future

---
 library/core/src/future/pending.rs | 2 --
 library/core/src/future/poll_fn.rs | 2 --
 library/core/src/future/ready.rs   | 2 --
 3 files changed, 6 deletions(-)

diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs
index 4fec219ede2bc..388b9e7bdb0e7 100644
--- a/library/core/src/future/pending.rs
+++ b/library/core/src/future/pending.rs
@@ -9,8 +9,6 @@ use crate::task::{Context, Poll};
 ///
 /// This `struct` is created by the [`pending`] function. See its
 /// documentation for more.
-///
-/// [`pending`]: fn.pending.html
 #[stable(feature = "future_readiness_fns", since = "1.48.0")]
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 pub struct Pending<T> {
diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs
index 9ab3bfcea1c71..3fe7eb88d0ff3 100644
--- a/library/core/src/future/poll_fn.rs
+++ b/library/core/src/future/poll_fn.rs
@@ -35,8 +35,6 @@ where
 ///
 /// This `struct` is created by the [`poll_fn`] function. See its
 /// documentation for more.
-///
-/// [`poll_fn`]: fn.poll_fn.html
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 #[unstable(feature = "future_poll_fn", issue = "72302")]
 pub struct PollFn<F> {
diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs
index fcfd8779b0ad2..ad93157c3454d 100644
--- a/library/core/src/future/ready.rs
+++ b/library/core/src/future/ready.rs
@@ -6,8 +6,6 @@ use crate::task::{Context, Poll};
 ///
 /// This `struct` is created by the [`ready`] function. See its
 /// documentation for more.
-///
-/// [`ready`]: fn.ready.html
 #[stable(feature = "future_readiness_fns", since = "1.48.0")]
 #[derive(Debug, Clone)]
 #[must_use = "futures do nothing unless you `.await` or poll them"]

From 4c92b3dc7d189bdff8f7e78be293d03e43466621 Mon Sep 17 00:00:00 2001
From: Poliorcetics <poliorcetics@users.noreply.github.com>
Date: Fri, 18 Sep 2020 09:52:35 +0200
Subject: [PATCH 18/21] Apply suggestions from code review

Co-authored-by: Joshua Nelson <joshua@yottadb.com>
---
 library/core/src/future/pending.rs | 2 +-
 library/core/src/future/poll_fn.rs | 2 +-
 library/core/src/future/ready.rs   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs
index 388b9e7bdb0e7..ab162638a1cfe 100644
--- a/library/core/src/future/pending.rs
+++ b/library/core/src/future/pending.rs
@@ -7,7 +7,7 @@ use crate::task::{Context, Poll};
 /// Creates a future which never resolves, representing a computation that never
 /// finishes.
 ///
-/// This `struct` is created by the [`pending`] function. See its
+/// This `struct` is created by [`pending()`]. See its
 /// documentation for more.
 #[stable(feature = "future_readiness_fns", since = "1.48.0")]
 #[must_use = "futures do nothing unless you `.await` or poll them"]
diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs
index 3fe7eb88d0ff3..f302cda09e721 100644
--- a/library/core/src/future/poll_fn.rs
+++ b/library/core/src/future/poll_fn.rs
@@ -33,7 +33,7 @@ where
 
 /// A Future that wraps a function returning `Poll`.
 ///
-/// This `struct` is created by the [`poll_fn`] function. See its
+/// This `struct` is created by [`poll_fn()`]. See its
 /// documentation for more.
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 #[unstable(feature = "future_poll_fn", issue = "72302")]
diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs
index ad93157c3454d..e98f5c570bf3c 100644
--- a/library/core/src/future/ready.rs
+++ b/library/core/src/future/ready.rs
@@ -4,7 +4,7 @@ use crate::task::{Context, Poll};
 
 /// Creates a future that is immediately ready with a value.
 ///
-/// This `struct` is created by the [`ready`] function. See its
+/// This `struct` is created by [`ready()`]. See its
 /// documentation for more.
 #[stable(feature = "future_readiness_fns", since = "1.48.0")]
 #[derive(Debug, Clone)]

From c5968e8a4b22aa9bff2a8b1ace5f0991aa396bf2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kornel=20Lesi=C5=84ski?= <kornel@geekhood.net>
Date: Wed, 16 Sep 2020 03:45:58 +0100
Subject: [PATCH 19/21] Let user see the full type of type-length limit error

---
 .../rustc_mir/src/monomorphize/collector.rs   | 66 +++++++++++--------
 .../ui/infinite/infinite-instantiation.stderr |  1 +
 src/test/ui/issues/issue-22638.stderr         |  1 +
 .../issue-37311.stderr                        |  1 +
 src/test/ui/issues/issue-67552.stderr         |  1 +
 src/test/ui/issues/issue-8727.stderr          |  1 +
 ...-38591-non-regular-dropck-recursion.stderr |  1 +
 src/test/ui/recursion/recursion.stderr        |  1 +
 src/test/ui/type_length_limit.stderr          |  3 +-
 9 files changed, 49 insertions(+), 27 deletions(-)

diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index 0dbb4b1015e79..a20094fd2c876 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -197,6 +197,7 @@ use rustc_session::config::EntryFnType;
 use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
 use smallvec::SmallVec;
 use std::iter;
+use std::path::PathBuf;
 
 #[derive(PartialEq)]
 pub enum MonoItemCollectionMode {
@@ -418,27 +419,38 @@ fn record_accesses<'a, 'tcx: 'a>(
     inlining_map.lock_mut().record_accesses(caller, &accesses);
 }
 
-// Shrinks string by keeping prefix and suffix of given sizes.
-fn shrink(s: String, before: usize, after: usize) -> String {
-    // An iterator of all byte positions including the end of the string.
-    let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len()));
-
-    let shrunk = format!(
-        "{before}...{after}",
-        before = &s[..positions().nth(before).unwrap_or(s.len())],
-        after = &s[positions().rev().nth(after).unwrap_or(0)..],
-    );
+/// Format instance name that is already known to be too long for rustc.
+/// Show only the first and last 32 characters to avoid blasting
+/// the user's terminal with thousands of lines of type-name.
+///
+/// If the type name is longer than before+after, it will be written to a file.
+fn shrunk_instance_name(
+    tcx: TyCtxt<'tcx>,
+    instance: &Instance<'tcx>,
+    before: usize,
+    after: usize,
+) -> (String, Option<PathBuf>) {
+    let s = instance.to_string();
 
     // Only use the shrunk version if it's really shorter.
     // This also avoids the case where before and after slices overlap.
-    if shrunk.len() < s.len() { shrunk } else { s }
-}
+    if s.chars().nth(before + after + 1).is_some() {
+        // An iterator of all byte positions including the end of the string.
+        let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len()));
+
+        let shrunk = format!(
+            "{before}...{after}",
+            before = &s[..positions().nth(before).unwrap_or(s.len())],
+            after = &s[positions().rev().nth(after).unwrap_or(0)..],
+        );
+
+        let path = tcx.output_filenames(LOCAL_CRATE).temp_path_ext("long-type.txt", None);
+        let written_to_path = std::fs::write(&path, s).ok().map(|_| path);
 
-// Format instance name that is already known to be too long for rustc.
-// Show only the first and last 32 characters to avoid blasting
-// the user's terminal with thousands of lines of type-name.
-fn shrunk_instance_name(instance: &Instance<'tcx>) -> String {
-    shrink(instance.to_string(), 32, 32)
+        (shrunk, written_to_path)
+    } else {
+        (s, None)
+    }
 }
 
 fn check_recursion_limit<'tcx>(
@@ -463,15 +475,16 @@ fn check_recursion_limit<'tcx>(
     // more than the recursion limit is assumed to be causing an
     // infinite expansion.
     if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) {
-        let error = format!(
-            "reached the recursion limit while instantiating `{}`",
-            shrunk_instance_name(&instance),
-        );
+        let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
+        let error = format!("reached the recursion limit while instantiating `{}`", shrunk);
         let mut err = tcx.sess.struct_span_fatal(span, &error);
         err.span_note(
             tcx.def_span(def_id),
             &format!("`{}` defined here", tcx.def_path_str(def_id)),
         );
+        if let Some(path) = written_to_path {
+            err.note(&format!("the full type name has been written to '{}'", path.display()));
+        }
         err.emit();
         FatalError.raise();
     }
@@ -500,12 +513,13 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
     //
     // Bail out in these cases to avoid that bad user experience.
     if !tcx.sess.type_length_limit().value_within_limit(type_length) {
-        let msg = format!(
-            "reached the type-length limit while instantiating `{}`",
-            shrunk_instance_name(&instance),
-        );
+        let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
+        let msg = format!("reached the type-length limit while instantiating `{}`", shrunk);
         let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg);
-        diag.note(&format!(
+        if let Some(path) = written_to_path {
+            diag.note(&format!("the full type name has been written to '{}'", path.display()));
+        }
+        diag.help(&format!(
             "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
             type_length
         ));
diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr
index d27d14842ce99..29829179c22ed 100644
--- a/src/test/ui/infinite/infinite-instantiation.stderr
+++ b/src/test/ui/infinite/infinite-instantiation.stderr
@@ -9,6 +9,7 @@ note: `function` defined here
    |
 LL | fn function<T:ToOpt + Clone>(counter: usize, t: T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: the full type name has been written to '$TEST_BUILD_DIR/infinite/infinite-instantiation/infinite-instantiation.long-type.txt'
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-22638.stderr b/src/test/ui/issues/issue-22638.stderr
index c4255b95b704e..11286011ec29a 100644
--- a/src/test/ui/issues/issue-22638.stderr
+++ b/src/test/ui/issues/issue-22638.stderr
@@ -9,6 +9,7 @@ note: `A::matches` defined here
    |
 LL |     pub fn matches<F: Fn()>(&self, f: &F) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-22638/issue-22638.long-type.txt'
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
index a94f190d6b25d..22918835844e4 100644
--- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
+++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
@@ -9,6 +9,7 @@ note: `<T as Foo>::recurse` defined here
    |
 LL |     fn recurse(&self) {
    |     ^^^^^^^^^^^^^^^^^
+   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt'
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr
index f3e73399b57ce..ac7635bd7f80c 100644
--- a/src/test/ui/issues/issue-67552.stderr
+++ b/src/test/ui/issues/issue-67552.stderr
@@ -11,6 +11,7 @@ LL | / fn rec<T>(mut it: T)
 LL | | where
 LL | |     T: Iterator,
    | |________________^
+   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-67552/issue-67552.long-type.txt'
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr
index 279e3ffbb4a41..82f6231d396ea 100644
--- a/src/test/ui/issues/issue-8727.stderr
+++ b/src/test/ui/issues/issue-8727.stderr
@@ -20,6 +20,7 @@ note: `generic` defined here
    |
 LL | fn generic<T>() {
    | ^^^^^^^^^^^^^^^
+   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-8727/issue-8727.long-type.txt'
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
index 4d77b3d295c00..3efe13b3de3d0 100644
--- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
+++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
@@ -21,6 +21,7 @@ LL | |     // SAFETY: see comment above
 LL | |     unsafe { drop_in_place(to_drop) }
 LL | | }
    | |_^
+   = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-38591-non-regular-dropck-recursion/issue-38591-non-regular-dropck-recursion.long-type.txt'
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr
index 085bf82ef8b93..082e784f0c9be 100644
--- a/src/test/ui/recursion/recursion.stderr
+++ b/src/test/ui/recursion/recursion.stderr
@@ -9,6 +9,7 @@ note: `test` defined here
    |
 LL | fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/recursion/recursion.long-type.txt'
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr
index cf3d64d734ba0..1c0a596a64cb9 100644
--- a/src/test/ui/type_length_limit.stderr
+++ b/src/test/ui/type_length_limit.stderr
@@ -4,7 +4,8 @@ error: reached the type-length limit while instantiating `std::mem::drop::<Optio
 LL | pub fn drop<T>(_x: T) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: consider adding a `#![type_length_limit="8"]` attribute to your crate
+   = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
+   = help: consider adding a `#![type_length_limit="8"]` attribute to your crate
 
 error: aborting due to previous error
 

From 3435683fd5930676b5a7ccd40dc08e4758e8b90a Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Thu, 17 Sep 2020 09:28:14 +0200
Subject: [PATCH 20/21] use `array_windows` instead of `windows` in the
 compiler

---
 compiler/rustc_data_structures/src/lib.rs              |  1 +
 compiler/rustc_data_structures/src/sorted_map.rs       |  4 ++--
 compiler/rustc_lint/src/lib.rs                         |  1 +
 compiler/rustc_lint/src/nonstandard_style.rs           |  4 ++--
 compiler/rustc_middle/src/lib.rs                       |  1 +
 compiler/rustc_middle/src/ty/context.rs                |  2 +-
 compiler/rustc_mir/src/lib.rs                          |  1 +
 .../rustc_mir/src/monomorphize/partitioning/mod.rs     |  8 +-------
 compiler/rustc_mir_build/src/lib.rs                    |  2 +-
 compiler/rustc_mir_build/src/thir/pattern/_match.rs    |  4 ++--
 compiler/rustc_span/src/lib.rs                         | 10 ++++++++--
 11 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 06718cc980312..3322edd18ccbd 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -8,6 +8,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![allow(incomplete_features)]
+#![feature(array_windows)]
 #![feature(control_flow_enum)]
 #![feature(in_band_lifetimes)]
 #![feature(unboxed_closures)]
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 856eb73e6297a..4807380595db7 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -34,7 +34,7 @@ impl<K: Ord, V> SortedMap<K, V> {
     /// and that there are no duplicates.
     #[inline]
     pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap<K, V> {
-        debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0));
+        debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0));
 
         SortedMap { data: elements }
     }
@@ -159,7 +159,7 @@ impl<K: Ord, V> SortedMap<K, V> {
             return;
         }
 
-        debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0));
+        debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0));
 
         let start_index = self.lookup_index_for(&elements[0].0);
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 0a14b16e274c8..b48592c103ca2 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -27,6 +27,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(test, feature(test))]
+#![feature(array_windows)]
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 24467f811726a..b3125f55d4d6e 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -70,9 +70,9 @@ fn is_camel_case(name: &str) -> bool {
     // ones (some scripts don't have a concept of upper/lowercase)
     !name.chars().next().unwrap().is_lowercase()
         && !name.contains("__")
-        && !name.chars().collect::<Vec<_>>().windows(2).any(|pair| {
+        && !name.chars().collect::<Vec<_>>().array_windows().any(|&[fst, snd]| {
             // contains a capitalisable character followed by, or preceded by, an underscore
-            char_has_case(pair[0]) && pair[1] == '_' || char_has_case(pair[1]) && pair[0] == '_'
+            char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_'
         })
 }
 
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index a675aae5b17d4..ac931028c010d 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -23,6 +23,7 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(array_windows)]
 #![feature(backtrace)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 56746666e2f1f..38c0441990b25 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2419,7 +2419,7 @@ impl<'tcx> TyCtxt<'tcx> {
         eps: &[ExistentialPredicate<'tcx>],
     ) -> &'tcx List<ExistentialPredicate<'tcx>> {
         assert!(!eps.is_empty());
-        assert!(eps.windows(2).all(|w| w[0].stable_cmp(self, &w[1]) != Ordering::Greater));
+        assert!(eps.array_windows().all(|[a, b]| a.stable_cmp(self, b) != Ordering::Greater));
         self._intern_existential_predicates(eps)
     }
 
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index 251037792c917..52b0a7e706769 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -6,6 +6,7 @@ Rust MIR: a lowered representation of Rust.
 
 #![feature(nll)]
 #![feature(in_band_lifetimes)]
+#![feature(array_windows)]
 #![feature(bindings_after_at)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
index b60beca688068..db6d3b2d912d6 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
@@ -277,14 +277,8 @@ where
 
     symbols.sort_by_key(|sym| sym.1);
 
-    for pair in symbols.windows(2) {
-        let sym1 = &pair[0].1;
-        let sym2 = &pair[1].1;
-
+    for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() {
         if sym1 == sym2 {
-            let mono_item1 = pair[0].0;
-            let mono_item2 = pair[1].0;
-
             let span1 = mono_item1.local_span(tcx);
             let span2 = mono_item2.local_span(tcx);
 
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index e55180ff4be52..714041ad4e874 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -1,7 +1,7 @@
 //! Construction of MIR from HIR.
 //!
 //! This crate also contains the match exhaustiveness and usefulness checking.
-
+#![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(const_fn)]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
index ad94740c16066..e71e1abd680b3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
@@ -2299,8 +2299,8 @@ fn split_grouped_constructors<'p, 'tcx>(
                 // interval into a constructor.
                 split_ctors.extend(
                     borders
-                        .windows(2)
-                        .filter_map(|window| match (window[0], window[1]) {
+                        .array_windows()
+                        .filter_map(|&[fst, snd]| match (fst, snd) {
                             (Border::JustBefore(n), Border::JustBefore(m)) => {
                                 if n < m {
                                     Some(IntRange { range: n..=(m - 1), ty, span })
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index e38cd516b91ac..e817fa56c55eb 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -5,6 +5,7 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(array_windows)]
 #![feature(crate_visibility_modifier)]
 #![feature(const_fn)]
 #![feature(const_panic)]
@@ -1158,7 +1159,12 @@ impl<S: Encoder> Encodable<S> for SourceFile {
                     let max_line_length = if lines.len() == 1 {
                         0
                     } else {
-                        lines.windows(2).map(|w| w[1] - w[0]).map(|bp| bp.to_usize()).max().unwrap()
+                        lines
+                            .array_windows()
+                            .map(|&[fst, snd]| snd - fst)
+                            .map(|bp| bp.to_usize())
+                            .max()
+                            .unwrap()
                     };
 
                     let bytes_per_diff: u8 = match max_line_length {
@@ -1173,7 +1179,7 @@ impl<S: Encoder> Encodable<S> for SourceFile {
                     // Encode the first element.
                     lines[0].encode(s)?;
 
-                    let diff_iter = (&lines[..]).windows(2).map(|w| (w[1] - w[0]));
+                    let diff_iter = lines[..].array_windows().map(|&[fst, snd]| snd - fst);
 
                     match bytes_per_diff {
                         1 => {

From bfb221b21e13e8fd71a8fc3a2df23e7f0e775df3 Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Thu, 17 Sep 2020 10:01:24 +0200
Subject: [PATCH 21/21] array pattern

---
 compiler/rustc_mir_build/src/thir/pattern/_match.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
index e71e1abd680b3..eddd2882406ba 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
@@ -2300,18 +2300,18 @@ fn split_grouped_constructors<'p, 'tcx>(
                 split_ctors.extend(
                     borders
                         .array_windows()
-                        .filter_map(|&[fst, snd]| match (fst, snd) {
-                            (Border::JustBefore(n), Border::JustBefore(m)) => {
+                        .filter_map(|&pair| match pair {
+                            [Border::JustBefore(n), Border::JustBefore(m)] => {
                                 if n < m {
                                     Some(IntRange { range: n..=(m - 1), ty, span })
                                 } else {
                                     None
                                 }
                             }
-                            (Border::JustBefore(n), Border::AfterMax) => {
+                            [Border::JustBefore(n), Border::AfterMax] => {
                                 Some(IntRange { range: n..=u128::MAX, ty, span })
                             }
-                            (Border::AfterMax, _) => None,
+                            [Border::AfterMax, _] => None,
                         })
                         .map(IntRange),
                 );