diff --git a/Cargo.lock b/Cargo.lock
index 8f110403eb842..d6fb659178764 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1242,9 +1242,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.1.14"
+version = "0.1.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
+checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
 dependencies = [
  "compiler_builtins",
  "libc",
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index ff28f4f603c9d..1a1c1618da40d 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -238,7 +238,7 @@ For targets: `powerpc-unknown-linux-gnu`
 - Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC
 - Operating System > Target OS = linux
 - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
+- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
 - C compiler > gcc version = 5.2.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
@@ -255,7 +255,7 @@ For targets: `powerpc64-unknown-linux-gnu`
 - Target options > Tune for CPU = power6 -- (+)
 - Operating System > Target OS = linux
 - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
+- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
 - C compiler > gcc version = 5.2.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
@@ -272,7 +272,7 @@ For targets: `s390x-unknown-linux-gnu`
 - Target options > Bitness = 64-bit
 - Operating System > Target OS = linux
 - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
+- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
 - C compiler > gcc version = 5.2.0
 - C compiler > gcc extra config = --with-arch=z10 -- LLVM's minimum support
 - C compiler > C++ = ENABLE -- to cross compile LLVM
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
similarity index 100%
rename from src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
rename to src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.12.2/002-newer-gcc.patch b/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/002-newer-gcc.patch
similarity index 100%
rename from src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.12.2/002-newer-gcc.patch
rename to src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/002-newer-gcc.patch
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config b/src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config
index 7df41da2bf76e..b358dce3cdfe8 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config
+++ b/src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config
@@ -290,7 +290,7 @@ CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # C-library
 #
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.12.2"
+CT_LIBC_VERSION="2.11.1"
 CT_LIBC_glibc=y
 # CT_LIBC_musl is not set
 # CT_LIBC_uClibc is not set
@@ -309,9 +309,9 @@ CT_THREADS="nptl"
 # CT_LIBC_GLIBC_V_2_14_1 is not set
 # CT_LIBC_GLIBC_V_2_14 is not set
 # CT_LIBC_GLIBC_V_2_13 is not set
-CT_LIBC_GLIBC_V_2_12_2=y
+# CT_LIBC_GLIBC_V_2_12_2 is not set
 # CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
+CT_LIBC_GLIBC_V_2_11_1=y
 # CT_LIBC_GLIBC_V_2_11 is not set
 # CT_LIBC_GLIBC_V_2_10_1 is not set
 # CT_LIBC_GLIBC_V_2_9 is not set
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
similarity index 100%
rename from src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
rename to src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.12.2/002-Prevent-inlining-in-PPC64-initfini.s.patch b/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/002-Prevent-inlining-in-PPC64-initfini.s.patch
similarity index 100%
rename from src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.12.2/002-Prevent-inlining-in-PPC64-initfini.s.patch
rename to src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/002-Prevent-inlining-in-PPC64-initfini.s.patch
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.12.2/003-newer-gcc.patch b/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/003-newer-gcc.patch
similarity index 100%
rename from src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.12.2/003-newer-gcc.patch
rename to src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/003-newer-gcc.patch
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config b/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config
index 4aab4f4fd4445..aa13119d50c19 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config
+++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config
@@ -290,7 +290,7 @@ CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # C-library
 #
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.12.2"
+CT_LIBC_VERSION="2.11.1"
 CT_LIBC_glibc=y
 # CT_LIBC_musl is not set
 # CT_LIBC_uClibc is not set
@@ -309,9 +309,9 @@ CT_THREADS="nptl"
 # CT_LIBC_GLIBC_V_2_14_1 is not set
 # CT_LIBC_GLIBC_V_2_14 is not set
 # CT_LIBC_GLIBC_V_2_13 is not set
-CT_LIBC_GLIBC_V_2_12_2=y
+# CT_LIBC_GLIBC_V_2_12_2 is not set
 # CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
+CT_LIBC_GLIBC_V_2_11_1=y
 # CT_LIBC_GLIBC_V_2_11 is not set
 # CT_LIBC_GLIBC_V_2_10_1 is not set
 # CT_LIBC_GLIBC_V_2_9 is not set
diff --git a/src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.11.1/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch
similarity index 100%
rename from src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch
rename to src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.11.1/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch
diff --git a/src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.2/002-newer-gcc.patch b/src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.11.1/002-newer-gcc.patch
similarity index 100%
rename from src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.2/002-newer-gcc.patch
rename to src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.11.1/002-newer-gcc.patch
diff --git a/src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config b/src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config
index cd1c41b02e312..c9c141afad131 100644
--- a/src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config
+++ b/src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config
@@ -270,7 +270,7 @@ CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # C-library
 #
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.12.2"
+CT_LIBC_VERSION="2.11.1"
 CT_LIBC_glibc=y
 # CT_LIBC_musl is not set
 # CT_LIBC_uClibc is not set
@@ -289,9 +289,9 @@ CT_THREADS="nptl"
 # CT_LIBC_GLIBC_V_2_14_1 is not set
 # CT_LIBC_GLIBC_V_2_14 is not set
 # CT_LIBC_GLIBC_V_2_13 is not set
-CT_LIBC_GLIBC_V_2_12_2=y
+# CT_LIBC_GLIBC_V_2_12_2 is not set
 # CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
+CT_LIBC_GLIBC_V_2_11_1=y
 # CT_LIBC_GLIBC_V_2_11 is not set
 # CT_LIBC_GLIBC_V_2_10_1 is not set
 # CT_LIBC_GLIBC_V_2_9 is not set
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 7392a678b0549..8e9a903522802 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -1095,6 +1095,9 @@ $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+                if exp == 0 {
+                    return Some(1);
+                }
                 let mut base = self;
                 let mut acc: Self = 1;
 
@@ -1105,15 +1108,11 @@ $EndFeature, "
                     exp /= 2;
                     base = try_opt!(base.checked_mul(base));
                 }
-
+                // since exp!=0, finally the exp must be 1.
                 // Deal with the final bit of the exponent separately, since
                 // squaring the base afterwards is not necessary and may cause a
                 // needless overflow.
-                if exp == 1 {
-                    acc = try_opt!(acc.checked_mul(base));
-                }
-
-                Some(acc)
+                Some(try_opt!(acc.checked_mul(base)))
             }
         }
 
@@ -1622,6 +1621,9 @@ $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+                if exp == 0 {
+                    return 1;
+                }
                 let mut base = self;
                 let mut acc: Self = 1;
 
@@ -1633,14 +1635,11 @@ $EndFeature, "
                     base = base.wrapping_mul(base);
                 }
 
+                // since exp!=0, finally the exp must be 1.
                 // Deal with the final bit of the exponent separately, since
                 // squaring the base afterwards is not necessary and may cause a
                 // needless overflow.
-                if exp == 1 {
-                    acc = acc.wrapping_mul(base);
-                }
-
-                acc
+                acc.wrapping_mul(base)
             }
         }
 
@@ -1989,6 +1988,9 @@ $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+                if exp == 0 {
+                    return (1,false);
+                }
                 let mut base = self;
                 let mut acc: Self = 1;
                 let mut overflown = false;
@@ -2007,16 +2009,13 @@ $EndFeature, "
                     overflown |= r.1;
                 }
 
+                // since exp!=0, finally the exp must be 1.
                 // Deal with the final bit of the exponent separately, since
                 // squaring the base afterwards is not necessary and may cause a
                 // needless overflow.
-                if exp == 1 {
-                    r = acc.overflowing_mul(base);
-                    acc = r.0;
-                    overflown |= r.1;
-                }
-
-                (acc, overflown)
+                r = acc.overflowing_mul(base);
+                r.1 |= overflown;
+                r
             }
         }
 
@@ -2040,6 +2039,9 @@ $EndFeature, "
             #[inline]
             #[rustc_inherit_overflow_checks]
             pub const fn pow(self, mut exp: u32) -> Self {
+                if exp == 0 {
+                    return 1;
+                }
                 let mut base = self;
                 let mut acc = 1;
 
@@ -2051,14 +2053,11 @@ $EndFeature, "
                     base = base * base;
                 }
 
+                // since exp!=0, finally the exp must be 1.
                 // Deal with the final bit of the exponent separately, since
                 // squaring the base afterwards is not necessary and may cause a
                 // needless overflow.
-                if exp == 1 {
-                    acc = acc * base;
-                }
-
-                acc
+                acc * base
             }
         }
 
@@ -3295,6 +3294,9 @@ assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+                if exp == 0 {
+                    return Some(1);
+                }
                 let mut base = self;
                 let mut acc: Self = 1;
 
@@ -3306,14 +3308,12 @@ assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, "
                     base = try_opt!(base.checked_mul(base));
                 }
 
+                // since exp!=0, finally the exp must be 1.
                 // Deal with the final bit of the exponent separately, since
                 // squaring the base afterwards is not necessary and may cause a
                 // needless overflow.
-                if exp == 1 {
-                    acc = try_opt!(acc.checked_mul(base));
-                }
 
-                Some(acc)
+                Some(try_opt!(acc.checked_mul(base)))
             }
         }
 
@@ -3704,6 +3704,9 @@ assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+                if exp == 0 {
+                    return 1;
+                }
                 let mut base = self;
                 let mut acc: Self = 1;
 
@@ -3715,14 +3718,11 @@ assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
                     base = base.wrapping_mul(base);
                 }
 
+                // since exp!=0, finally the exp must be 1.
                 // Deal with the final bit of the exponent separately, since
                 // squaring the base afterwards is not necessary and may cause a
                 // needless overflow.
-                if exp == 1 {
-                    acc = acc.wrapping_mul(base);
-                }
-
-                acc
+                acc.wrapping_mul(base)
             }
         }
 
@@ -4029,6 +4029,9 @@ assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+                if exp == 0{
+                    return (1,false);
+                }
                 let mut base = self;
                 let mut acc: Self = 1;
                 let mut overflown = false;
@@ -4047,16 +4050,14 @@ assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
                     overflown |= r.1;
                 }
 
+                // since exp!=0, finally the exp must be 1.
                 // Deal with the final bit of the exponent separately, since
                 // squaring the base afterwards is not necessary and may cause a
                 // needless overflow.
-                if exp == 1 {
-                    r = acc.overflowing_mul(base);
-                    acc = r.0;
-                    overflown |= r.1;
-                }
+                r = acc.overflowing_mul(base);
+                r.1 |= overflown;
 
-                (acc, overflown)
+                r
             }
         }
 
@@ -4077,6 +4078,9 @@ Basic usage:
         #[inline]
         #[rustc_inherit_overflow_checks]
         pub const fn pow(self, mut exp: u32) -> Self {
+            if exp == 0 {
+                return 1;
+            }
             let mut base = self;
             let mut acc = 1;
 
@@ -4088,14 +4092,11 @@ Basic usage:
                 base = base * base;
             }
 
+            // since exp!=0, finally the exp must be 1.
             // Deal with the final bit of the exponent separately, since
             // squaring the base afterwards is not necessary and may cause a
             // needless overflow.
-            if exp == 1 {
-                acc = acc * base;
-            }
-
-            acc
+            acc * base
         }
     }
 
diff --git a/src/libcore/tests/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs
index 8396a0dd62db9..58a585669122c 100644
--- a/src/libcore/tests/num/int_macros.rs
+++ b/src/libcore/tests/num/int_macros.rs
@@ -255,12 +255,43 @@ macro_rules! int_module {
             #[test]
             fn test_pow() {
                 let mut r = 2 as $T;
-
                 assert_eq!(r.pow(2), 4 as $T);
                 assert_eq!(r.pow(0), 1 as $T);
+                assert_eq!(r.wrapping_pow(2), 4 as $T);
+                assert_eq!(r.wrapping_pow(0), 1 as $T);
+                assert_eq!(r.checked_pow(2), Some(4 as $T));
+                assert_eq!(r.checked_pow(0), Some(1 as $T));
+                assert_eq!(r.overflowing_pow(2), (4 as $T, false));
+                assert_eq!(r.overflowing_pow(0), (1 as $T, false));
+                assert_eq!(r.saturating_pow(2), 4 as $T);
+                assert_eq!(r.saturating_pow(0), 1 as $T);
+
+                r = MAX;
+                // use `^` to represent .pow() with no overflow.
+                // if itest::MAX == 2^j-1, then itest is a `j` bit int,
+                // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
+                // thussaturating_pow the overflowing result is exactly 1.
+                assert_eq!(r.wrapping_pow(2), 1 as $T);
+                assert_eq!(r.checked_pow(2), None);
+                assert_eq!(r.overflowing_pow(2), (1 as $T, true));
+                assert_eq!(r.saturating_pow(2), MAX);
+                //test for negative exponent.
                 r = -2 as $T;
                 assert_eq!(r.pow(2), 4 as $T);
                 assert_eq!(r.pow(3), -8 as $T);
+                assert_eq!(r.pow(0), 1 as $T);
+                assert_eq!(r.wrapping_pow(2), 4 as $T);
+                assert_eq!(r.wrapping_pow(3), -8 as $T);
+                assert_eq!(r.wrapping_pow(0), 1 as $T);
+                assert_eq!(r.checked_pow(2), Some(4 as $T));
+                assert_eq!(r.checked_pow(3), Some(-8 as $T));
+                assert_eq!(r.checked_pow(0), Some(1 as $T));
+                assert_eq!(r.overflowing_pow(2), (4 as $T, false));
+                assert_eq!(r.overflowing_pow(3), (-8 as $T, false));
+                assert_eq!(r.overflowing_pow(0), (1 as $T, false));
+                assert_eq!(r.saturating_pow(2), 4 as $T);
+                assert_eq!(r.saturating_pow(3), -8 as $T);
+                assert_eq!(r.saturating_pow(0), 1 as $T);
             }
         }
     };
diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs
index 8f1ca8e6fac2c..b84a8a7d9f88b 100644
--- a/src/libcore/tests/num/uint_macros.rs
+++ b/src/libcore/tests/num/uint_macros.rs
@@ -184,6 +184,31 @@ macro_rules! uint_module {
                 assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>);
                 assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>);
             }
+
+            #[test]
+            fn test_pow() {
+                let mut r = 2 as $T;
+                assert_eq!(r.pow(2), 4 as $T);
+                assert_eq!(r.pow(0), 1 as $T);
+                assert_eq!(r.wrapping_pow(2), 4 as $T);
+                assert_eq!(r.wrapping_pow(0), 1 as $T);
+                assert_eq!(r.checked_pow(2), Some(4 as $T));
+                assert_eq!(r.checked_pow(0), Some(1 as $T));
+                assert_eq!(r.overflowing_pow(2), (4 as $T, false));
+                assert_eq!(r.overflowing_pow(0), (1 as $T, false));
+                assert_eq!(r.saturating_pow(2), 4 as $T);
+                assert_eq!(r.saturating_pow(0), 1 as $T);
+
+                r = MAX;
+                // use `^` to represent .pow() with no overflow.
+                // if itest::MAX == 2^j-1, then itest is a `j` bit int,
+                // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
+                // thussaturating_pow the overflowing result is exactly 1.
+                assert_eq!(r.wrapping_pow(2), 1 as $T);
+                assert_eq!(r.checked_pow(2), None);
+                assert_eq!(r.overflowing_pow(2), (1 as $T, true));
+                assert_eq!(r.saturating_pow(2), MAX);
+            }
         }
     };
 }
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index ff905faa95a9f..063246f79fe36 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -1402,8 +1402,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
 
         debug!("note_type_err(diag={:?})", diag);
+        enum Mismatch<'a> {
+            Variable(ty::error::ExpectedFound<Ty<'a>>),
+            Fixed(&'static str),
+        }
         let (expected_found, exp_found, is_simple_error) = match values {
-            None => (None, None, false),
+            None => (None, Mismatch::Fixed("type"), false),
             Some(values) => {
                 let (is_simple_error, exp_found) = match values {
                     ValuePairs::Types(exp_found) => {
@@ -1417,9 +1421,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         )
                         .report(diag);
 
-                        (is_simple_err, Some(exp_found))
+                        (is_simple_err, Mismatch::Variable(exp_found))
                     }
-                    _ => (false, None),
+                    ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
+                    _ => (false, Mismatch::Fixed("type")),
                 };
                 let vals = match self.values_str(&values) {
                     Some((expected, found)) => Some((expected, found)),
@@ -1445,8 +1450,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
         };
         if let Some((expected, found)) = expected_found {
-            let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string());
-            let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string());
+            let expected_label = match exp_found {
+                Mismatch::Variable(ef) => ef.expected.prefix_string(),
+                Mismatch::Fixed(s) => s.into(),
+            };
+            let found_label = match exp_found {
+                Mismatch::Variable(ef) => ef.found.prefix_string(),
+                Mismatch::Fixed(s) => s.into(),
+            };
+            let exp_found = match exp_found {
+                Mismatch::Variable(exp_found) => Some(exp_found),
+                Mismatch::Fixed(_) => None,
+            };
             match (&terr, expected == found) {
                 (TypeError::Sorts(values), extra) => {
                     let sort_string = |ty: Ty<'tcx>| match (extra, &ty.kind) {
@@ -1499,6 +1514,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 }
             }
         }
+        let exp_found = match exp_found {
+            Mismatch::Variable(exp_found) => Some(exp_found),
+            Mismatch::Fixed(_) => None,
+        };
         if let Some(exp_found) = exp_found {
             self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
         }
diff --git a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
index dd970d800fba0..8521f900988e4 100644
--- a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
@@ -60,9 +60,7 @@ impl OutlivesSuggestionBuilder {
             // Don't give suggestions for upvars, closure return types, or other unnamable
             // regions.
             RegionNameSource::SynthesizedFreeEnvRegion(..)
-            | RegionNameSource::CannotMatchHirTy(..)
-            | RegionNameSource::MatchedHirTy(..)
-            | RegionNameSource::MatchedAdtAndSegment(..)
+            | RegionNameSource::AnonRegionFromArgument(..)
             | RegionNameSource::AnonRegionFromUpvar(..)
             | RegionNameSource::AnonRegionFromOutput(..)
             | RegionNameSource::AnonRegionFromYieldTy(..)
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
index 26c2aea41d5dc..cc8a5e0768cba 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -19,7 +19,7 @@ use crate::borrow_check::{
     MirBorrowckCtxt,
 };
 
-use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
+use super::{OutlivesSuggestionBuilder, RegionName};
 
 impl ConstraintDescription for ConstraintCategory {
     fn description(&self) -> &'static str {
@@ -396,18 +396,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             diag.span_label(upvar_span, "variable captured here");
         }
 
-        match self.give_region_a_name(*outlived_fr).unwrap().source {
-            RegionNameSource::NamedEarlyBoundRegion(fr_span)
-            | RegionNameSource::NamedFreeRegion(fr_span)
-            | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
-            | RegionNameSource::CannotMatchHirTy(fr_span, _)
-            | RegionNameSource::MatchedHirTy(fr_span)
-            | RegionNameSource::MatchedAdtAndSegment(fr_span)
-            | RegionNameSource::AnonRegionFromUpvar(fr_span, _)
-            | RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
-                diag.span_label(fr_span, "inferred to be a `FnMut` closure");
-            }
-            _ => {}
+        if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
+            diag.span_label(fr_span, "inferred to be a `FnMut` closure");
         }
 
         diag.note(
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
index 2240eb81e1fa7..32195adc60ef8 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
@@ -34,13 +34,8 @@ crate enum RegionNameSource {
     Static,
     /// The free region corresponding to the environment of a closure.
     SynthesizedFreeEnvRegion(Span, String),
-    /// The region name corresponds to a region where the type annotation is completely missing
-    /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
-    CannotMatchHirTy(Span, String),
-    /// The region name corresponds a reference that was found by traversing the type in the HIR.
-    MatchedHirTy(Span),
-    /// A region name from the generics list of a struct/enum/union.
-    MatchedAdtAndSegment(Span),
+    /// The region corresponding to an argument.
+    AnonRegionFromArgument(RegionNameHighlight),
     /// The region corresponding to a closure upvar.
     AnonRegionFromUpvar(Span, String),
     /// The region corresponding to the return type of a closure.
@@ -51,6 +46,19 @@ crate enum RegionNameSource {
     AnonRegionFromAsyncFn(Span),
 }
 
+/// Describes what to highlight to explain to the user that we're giving an anonymous region a
+/// synthesized name, and how to highlight it.
+#[derive(Debug, Clone)]
+crate enum RegionNameHighlight {
+    /// The anonymous region corresponds to a reference that was found by traversing the type in the HIR.
+    MatchedHirTy(Span),
+    /// The anonymous region corresponds to a `'_` in the generics list of a struct/enum/union.
+    MatchedAdtAndSegment(Span),
+    /// The anonymous region corresponds to a region where the type annotation is completely missing
+    /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
+    CannotMatchHirTy(Span, String),
+}
+
 impl RegionName {
     crate fn was_named(&self) -> bool {
         match self.source {
@@ -58,9 +66,7 @@ impl RegionName {
             | RegionNameSource::NamedFreeRegion(..)
             | RegionNameSource::Static => true,
             RegionNameSource::SynthesizedFreeEnvRegion(..)
-            | RegionNameSource::CannotMatchHirTy(..)
-            | RegionNameSource::MatchedHirTy(..)
-            | RegionNameSource::MatchedAdtAndSegment(..)
+            | RegionNameSource::AnonRegionFromArgument(..)
             | RegionNameSource::AnonRegionFromUpvar(..)
             | RegionNameSource::AnonRegionFromOutput(..)
             | RegionNameSource::AnonRegionFromYieldTy(..)
@@ -68,6 +74,24 @@ impl RegionName {
         }
     }
 
+    crate fn span(&self) -> Option<Span> {
+        match self.source {
+            RegionNameSource::Static => None,
+            RegionNameSource::NamedEarlyBoundRegion(span)
+            | RegionNameSource::NamedFreeRegion(span)
+            | RegionNameSource::SynthesizedFreeEnvRegion(span, _)
+            | RegionNameSource::AnonRegionFromUpvar(span, _)
+            | RegionNameSource::AnonRegionFromOutput(span, _, _)
+            | RegionNameSource::AnonRegionFromYieldTy(span, _)
+            | RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span),
+            RegionNameSource::AnonRegionFromArgument(ref highlight) => match *highlight {
+                RegionNameHighlight::MatchedHirTy(span)
+                | RegionNameHighlight::MatchedAdtAndSegment(span)
+                | RegionNameHighlight::CannotMatchHirTy(span, _) => Some(span),
+            },
+        }
+    }
+
     crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
         match &self.source {
             RegionNameSource::NamedFreeRegion(span)
@@ -81,17 +105,22 @@ impl RegionName {
                 );
                 diag.note(&note);
             }
-            RegionNameSource::CannotMatchHirTy(span, type_name) => {
+            RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy(
+                span,
+                type_name,
+            )) => {
                 diag.span_label(*span, format!("has type `{}`", type_name));
             }
-            RegionNameSource::MatchedHirTy(span)
+            RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span))
             | RegionNameSource::AnonRegionFromAsyncFn(span) => {
                 diag.span_label(
                     *span,
                     format!("let's call the lifetime of this reference `{}`", self),
                 );
             }
-            RegionNameSource::MatchedAdtAndSegment(span) => {
+            RegionNameSource::AnonRegionFromArgument(
+                RegionNameHighlight::MatchedAdtAndSegment(span),
+            ) => {
                 diag.span_label(*span, format!("let's call this `{}`", self));
             }
             RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
@@ -307,21 +336,31 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
 
         let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys
             [implicit_inputs + argument_index];
-        if let Some(region_name) =
-            self.give_name_if_we_can_match_hir_ty_from_argument(fr, arg_ty, argument_index)
-        {
-            return Some(region_name);
-        }
+        let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
+            &self.body,
+            &self.local_names,
+            argument_index,
+        );
 
-        self.give_name_if_we_cannot_match_hir_ty(fr, arg_ty)
+        self.get_argument_hir_ty_for_highlighting(argument_index)
+            .and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty))
+            .or_else(|| {
+                // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to
+                // the anonymous region. If it succeeds, the `synthesize_region_name` call below
+                // will increment the counter, "reserving" the number we just used.
+                let counter = *self.next_region_name.try_borrow().unwrap();
+                self.highlight_if_we_cannot_match_hir_ty(fr, arg_ty, span, counter)
+            })
+            .map(|highlight| RegionName {
+                name: self.synthesize_region_name(),
+                source: RegionNameSource::AnonRegionFromArgument(highlight),
+            })
     }
 
-    fn give_name_if_we_can_match_hir_ty_from_argument(
+    fn get_argument_hir_ty_for_highlighting(
         &self,
-        needle_fr: RegionVid,
-        argument_ty: Ty<'tcx>,
         argument_index: usize,
-    ) -> Option<RegionName> {
+    ) -> Option<&hir::Ty<'tcx>> {
         let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
         let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
         let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
@@ -333,7 +372,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             // (`give_name_if_anonymous_region_appears_in_arguments`).
             hir::TyKind::Infer => None,
 
-            _ => self.give_name_if_we_can_match_hir_ty(needle_fr, argument_ty, argument_hir_ty),
+            _ => Some(argument_hir_ty),
         }
     }
 
@@ -348,42 +387,28 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     ///  |          |  has type `&'1 u32`
     ///  |          has type `&'2 u32`
     /// ```
-    fn give_name_if_we_cannot_match_hir_ty(
+    fn highlight_if_we_cannot_match_hir_ty(
         &self,
         needle_fr: RegionVid,
-        argument_ty: Ty<'tcx>,
-    ) -> Option<RegionName> {
-        let counter = *self.next_region_name.try_borrow().unwrap();
+        ty: Ty<'tcx>,
+        span: Span,
+        counter: usize,
+    ) -> Option<RegionNameHighlight> {
         let mut highlight = RegionHighlightMode::default();
         highlight.highlighting_region_vid(needle_fr, counter);
-        let type_name = self.infcx.extract_type_name(&argument_ty, Some(highlight)).0;
+        let type_name = self.infcx.extract_type_name(&ty, Some(highlight)).0;
 
         debug!(
-            "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
+            "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
             type_name, needle_fr
         );
-        let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
+        if type_name.find(&format!("'{}", counter)).is_some() {
             // Only add a label if we can confirm that a region was labelled.
-            let argument_index =
-                self.regioncx.get_argument_index_for_region(self.infcx.tcx, needle_fr)?;
-            let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
-                &self.body,
-                &self.local_names,
-                argument_index,
-            );
-
-            Some(RegionName {
-                // This counter value will already have been used, so this function will increment
-                // it so the next value will be used next and return the region name that would
-                // have been used.
-                name: self.synthesize_region_name(),
-                source: RegionNameSource::CannotMatchHirTy(span, type_name),
-            })
+
+            Some(RegionNameHighlight::CannotMatchHirTy(span, type_name))
         } else {
             None
-        };
-
-        assigned_region_name
+        }
     }
 
     /// Attempts to highlight the specific part of a type annotation
@@ -395,9 +420,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     ///  |                - let's call the lifetime of this reference `'1`
     /// ```
     ///
-    /// the way this works is that we match up `argument_ty`, which is
+    /// the way this works is that we match up `ty`, which is
     /// a `Ty<'tcx>` (the internal form of the type) with
-    /// `argument_hir_ty`, a `hir::Ty` (the syntax of the type
+    /// `hir_ty`, a `hir::Ty` (the syntax of the type
     /// annotation). We are descending through the types stepwise,
     /// looking in to find the region `needle_fr` in the internal
     /// type. Once we find that, we can use the span of the `hir::Ty`
@@ -407,18 +432,17 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     /// keep track of the **closest** type we've found. If we fail to
     /// find the exact `&` or `'_` to highlight, then we may fall back
     /// to highlighting that closest type instead.
-    fn give_name_if_we_can_match_hir_ty(
+    fn highlight_if_we_can_match_hir_ty(
         &self,
         needle_fr: RegionVid,
-        argument_ty: Ty<'tcx>,
-        argument_hir_ty: &hir::Ty<'_>,
-    ) -> Option<RegionName> {
-        let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> =
-            &mut vec![(argument_ty, argument_hir_ty)];
+        ty: Ty<'tcx>,
+        hir_ty: &hir::Ty<'_>,
+    ) -> Option<RegionNameHighlight> {
+        let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)];
 
         while let Some((ty, hir_ty)) = search_stack.pop() {
             match (&ty.kind, &hir_ty.kind) {
-                // Check if the `argument_ty` is `&'X ..` where `'X`
+                // Check if the `ty` is `&'X ..` where `'X`
                 // is the region we are looking for -- if so, and we have a `&T`
                 // on the RHS, then we want to highlight the `&` like so:
                 //
@@ -429,16 +453,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     hir::TyKind::Rptr(_lifetime, referent_hir_ty),
                 ) => {
                     if region.to_region_vid() == needle_fr {
-                        let region_name = self.synthesize_region_name();
-
                         // Just grab the first character, the `&`.
                         let source_map = self.infcx.tcx.sess.source_map();
                         let ampersand_span = source_map.start_point(hir_ty.span);
 
-                        return Some(RegionName {
-                            name: region_name,
-                            source: RegionNameSource::MatchedHirTy(ampersand_span),
-                        });
+                        return Some(RegionNameHighlight::MatchedHirTy(ampersand_span));
                     }
 
                     // Otherwise, let's descend into the referent types.
@@ -458,13 +477,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                         Res::Def(DefKind::TyAlias, _) => (),
                         _ => {
                             if let Some(last_segment) = path.segments.last() {
-                                if let Some(name) = self.match_adt_and_segment(
+                                if let Some(highlight) = self.match_adt_and_segment(
                                     substs,
                                     needle_fr,
                                     last_segment,
                                     search_stack,
                                 ) {
-                                    return Some(name);
+                                    return Some(highlight);
                                 }
                             }
                         }
@@ -507,7 +526,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         needle_fr: RegionVid,
         last_segment: &'hir hir::PathSegment<'hir>,
         search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
-    ) -> Option<RegionName> {
+    ) -> Option<RegionNameHighlight> {
         // Did the user give explicit arguments? (e.g., `Foo<..>`)
         let args = last_segment.args.as_ref()?;
         let lifetime =
@@ -517,12 +536,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             | hir::LifetimeName::Error
             | hir::LifetimeName::Static
             | hir::LifetimeName::Underscore => {
-                let region_name = self.synthesize_region_name();
-                let ampersand_span = lifetime.span;
-                Some(RegionName {
-                    name: region_name,
-                    source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
-                })
+                let lifetime_span = lifetime.span;
+                Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
             }
 
             hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 3073bf53afd78..b3dedd5b8223e 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -28,9 +28,9 @@ use rustc_trait_selection::traits;
 
 use crate::const_eval::error_to_const_error;
 use crate::interpret::{
-    self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, LocalState,
-    LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
-    ScalarMaybeUninit, StackPopCleanup,
+    self, compile_time_machine, truncate, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
+    LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
+    Pointer, ScalarMaybeUninit, StackPopCleanup,
 };
 use crate::transform::{MirPass, MirSource};
 
@@ -527,11 +527,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         right: &Operand<'tcx>,
         source_info: SourceInfo,
     ) -> Option<()> {
-        let r =
-            self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?))?;
+        let r = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?));
         let l = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(left, None)?));
         // Check for exceeding shifts *even if* we cannot evaluate the LHS.
         if op == BinOp::Shr || op == BinOp::Shl {
+            let r = r?;
             // We need the type of the LHS. We cannot use `place_layout` as that is the type
             // of the result, which for checked binops is not the same!
             let left_ty = left.ty(&self.local_decls, self.tcx);
@@ -564,21 +564,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             }
         }
 
-        let l = l?;
-
-        // The remaining operators are handled through `overflowing_binary_op`.
-        if self.use_ecx(|this| {
-            let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
-            Ok(overflow)
-        })? {
-            self.report_assert_as_lint(
-                lint::builtin::ARITHMETIC_OVERFLOW,
-                source_info,
-                "this arithmetic operation will overflow",
-                AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
-            )?;
+        if let (Some(l), Some(r)) = (l, r) {
+            // The remaining operators are handled through `overflowing_binary_op`.
+            if self.use_ecx(|this| {
+                let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
+                Ok(overflow)
+            })? {
+                self.report_assert_as_lint(
+                    lint::builtin::ARITHMETIC_OVERFLOW,
+                    source_info,
+                    "this arithmetic operation will overflow",
+                    AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
+                )?;
+            }
         }
-
         Some(())
     }
 
@@ -659,9 +658,74 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             return None;
         }
 
+        if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 3 {
+            self.eval_rvalue_with_identities(rvalue, place)
+        } else {
+            self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place))
+        }
+    }
+
+    // Attempt to use albegraic identities to eliminate constant expressions
+    fn eval_rvalue_with_identities(
+        &mut self,
+        rvalue: &Rvalue<'tcx>,
+        place: Place<'tcx>,
+    ) -> Option<()> {
         self.use_ecx(|this| {
-            trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place);
-            this.ecx.eval_rvalue_into_place(rvalue, place)?;
+            match rvalue {
+                Rvalue::BinaryOp(op, left, right) | Rvalue::CheckedBinaryOp(op, left, right) => {
+                    let l = this.ecx.eval_operand(left, None);
+                    let r = this.ecx.eval_operand(right, None);
+
+                    let const_arg = match (l, r) {
+                        (Ok(x), Err(_)) | (Err(_), Ok(x)) => this.ecx.read_immediate(x)?,
+                        (Err(e), Err(_)) => return Err(e),
+                        (Ok(_), Ok(_)) => {
+                            this.ecx.eval_rvalue_into_place(rvalue, place)?;
+                            return Ok(());
+                        }
+                    };
+
+                    let arg_value =
+                        this.ecx.force_bits(const_arg.to_scalar()?, const_arg.layout.size)?;
+                    let dest = this.ecx.eval_place(place)?;
+
+                    match op {
+                        BinOp::BitAnd => {
+                            if arg_value == 0 {
+                                this.ecx.write_immediate(*const_arg, dest)?;
+                            }
+                        }
+                        BinOp::BitOr => {
+                            if arg_value == truncate(u128::MAX, const_arg.layout.size)
+                                || (const_arg.layout.ty.is_bool() && arg_value == 1)
+                            {
+                                this.ecx.write_immediate(*const_arg, dest)?;
+                            }
+                        }
+                        BinOp::Mul => {
+                            if const_arg.layout.ty.is_integral() && arg_value == 0 {
+                                if let Rvalue::CheckedBinaryOp(_, _, _) = rvalue {
+                                    let val = Immediate::ScalarPair(
+                                        const_arg.to_scalar()?.into(),
+                                        Scalar::from_bool(false).into(),
+                                    );
+                                    this.ecx.write_immediate(val, dest)?;
+                                } else {
+                                    this.ecx.write_immediate(*const_arg, dest)?;
+                                }
+                            }
+                        }
+                        _ => {
+                            this.ecx.eval_rvalue_into_place(rvalue, place)?;
+                        }
+                    }
+                }
+                _ => {
+                    this.ecx.eval_rvalue_into_place(rvalue, place)?;
+                }
+            }
+
             Ok(())
         })
     }
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 261c2031364f6..4b5ab03df4327 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -1506,18 +1506,24 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         pat.walk(&mut |pat| {
             debug!("resolve_pattern pat={:?} node={:?}", pat, pat.kind);
             match pat.kind {
-                // In tuple struct patterns ignore the invalid `ident @ ...`.
-                // It will be handled as an error by the AST lowering.
-                PatKind::Ident(bmode, ident, ref sub)
-                    if !(is_tuple_struct_pat && sub.as_ref().filter(|p| p.is_rest()).is_some()) =>
-                {
-                    // First try to resolve the identifier as some existing entity,
-                    // then fall back to a fresh binding.
-                    let has_sub = sub.is_some();
-                    let res = self
-                        .try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
-                        .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
-                    self.r.record_partial_res(pat.id, PartialRes::new(res));
+                PatKind::Ident(bmode, ident, ref sub) => {
+                    if is_tuple_struct_pat && sub.as_ref().filter(|p| p.is_rest()).is_some() {
+                        // In tuple struct patterns ignore the invalid `ident @ ...`.
+                        // It will be handled as an error by the AST lowering.
+                        self.r
+                            .session
+                            .delay_span_bug(ident.span, "ident in tuple pattern is invalid");
+                    } else {
+                        // First try to resolve the identifier as some existing entity,
+                        // then fall back to a fresh binding.
+                        let has_sub = sub.is_some();
+                        let res = self
+                            .try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
+                            .unwrap_or_else(|| {
+                                self.fresh_binding(ident, pat.id, pat_src, bindings)
+                            });
+                        self.r.record_partial_res(pat.id, PartialRes::new(res));
+                    }
                 }
                 PatKind::TupleStruct(ref path, ..) => {
                     self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct(pat.span));
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index 8138dfa580d80..2c1e71c64c4e5 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -40,7 +40,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
 fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
-hermit-abi = { version = "0.1.14", features = ['rustc-dep-of-std'] }
+hermit-abi = { version = "0.1.15", features = ['rustc-dep-of-std'] }
 
 [target.wasm32-wasi.dependencies]
 wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
diff --git a/src/libstd/sys/hermit/condvar.rs b/src/libstd/sys/hermit/condvar.rs
index 132e579b3a5cb..52c8c3b17e826 100644
--- a/src/libstd/sys/hermit/condvar.rs
+++ b/src/libstd/sys/hermit/condvar.rs
@@ -1,60 +1,64 @@
-use crate::cmp;
+use crate::ffi::c_void;
+use crate::ptr;
+use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
 use crate::sys::hermit::abi;
 use crate::sys::mutex::Mutex;
 use crate::time::Duration;
 
+// The implementation is inspired by Andrew D. Birrell's paper
+// "Implementing Condition Variables with Semaphores"
+
 pub struct Condvar {
-    identifier: usize,
+    counter: AtomicUsize,
+    sem1: *const c_void,
+    sem2: *const c_void,
 }
 
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
 impl Condvar {
     pub const fn new() -> Condvar {
-        Condvar { identifier: 0 }
+        Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
     }
 
     pub unsafe fn init(&mut self) {
-        let _ = abi::init_queue(self.id());
+        let _ = abi::sem_init(&mut self.sem1 as *mut *const c_void, 0);
+        let _ = abi::sem_init(&mut self.sem2 as *mut *const c_void, 0);
     }
 
     pub unsafe fn notify_one(&self) {
-        let _ = abi::notify(self.id(), 1);
+        if self.counter.load(SeqCst) > 0 {
+            self.counter.fetch_sub(1, SeqCst);
+            abi::sem_post(self.sem1);
+            abi::sem_timedwait(self.sem2, 0);
+        }
     }
 
-    #[inline]
     pub unsafe fn notify_all(&self) {
-        let _ = abi::notify(self.id(), -1 /* =all */);
+        let counter = self.counter.swap(0, SeqCst);
+        for _ in 0..counter {
+            abi::sem_post(self.sem1);
+        }
+        for _ in 0..counter {
+            abi::sem_timedwait(self.sem2, 0);
+        }
     }
 
     pub unsafe fn wait(&self, mutex: &Mutex) {
-        // add current task to the wait queue
-        let _ = abi::add_queue(self.id(), -1 /* no timeout */);
+        self.counter.fetch_add(1, SeqCst);
         mutex.unlock();
-        let _ = abi::wait(self.id());
+        abi::sem_timedwait(self.sem1, 0);
+        abi::sem_post(self.sem2);
         mutex.lock();
     }
 
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        let nanos = dur.as_nanos();
-        let nanos = cmp::min(i64::MAX as u128, nanos);
-
-        // add current task to the wait queue
-        let _ = abi::add_queue(self.id(), nanos as i64);
-
-        mutex.unlock();
-        // If the return value is !0 then a timeout happened, so we return
-        // `false` as we weren't actually notified.
-        let ret = abi::wait(self.id()) == 0;
-        mutex.lock();
-
-        ret
+    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+        panic!("wait_timeout not supported on hermit");
     }
 
     pub unsafe fn destroy(&self) {
-        let _ = abi::destroy_queue(self.id());
-    }
-
-    #[inline]
-    fn id(&self) -> usize {
-        &self.identifier as *const usize as usize
+        let _ = abi::sem_destroy(self.sem1);
+        let _ = abi::sem_destroy(self.sem2);
     }
 }
diff --git a/src/libstd/sys/hermit/rwlock.rs b/src/libstd/sys/hermit/rwlock.rs
index c19799af3c7ee..06442e925f4c8 100644
--- a/src/libstd/sys/hermit/rwlock.rs
+++ b/src/libstd/sys/hermit/rwlock.rs
@@ -1,49 +1,144 @@
-use super::mutex::Mutex;
+use crate::cell::UnsafeCell;
+use crate::sys::condvar::Condvar;
+use crate::sys::mutex::Mutex;
 
 pub struct RWLock {
-    mutex: Mutex,
+    lock: Mutex,
+    cond: Condvar,
+    state: UnsafeCell<State>,
+}
+
+enum State {
+    Unlocked,
+    Reading(usize),
+    Writing,
 }
 
 unsafe impl Send for RWLock {}
 unsafe impl Sync for RWLock {}
 
+// This rwlock implementation is a relatively simple implementation which has a
+// condition variable for readers/writers as well as a mutex protecting the
+// internal state of the lock. A current downside of the implementation is that
+// unlocking the lock will notify *all* waiters rather than just readers or just
+// writers. This can cause lots of "thundering stampede" problems. While
+// hopefully correct this implementation is very likely to want to be changed in
+// the future.
+
 impl RWLock {
     pub const fn new() -> RWLock {
-        RWLock { mutex: Mutex::new() }
+        RWLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
     }
 
     #[inline]
     pub unsafe fn read(&self) {
-        self.mutex.lock();
+        self.lock.lock();
+        while !(*self.state.get()).inc_readers() {
+            self.cond.wait(&self.lock);
+        }
+        self.lock.unlock();
     }
 
     #[inline]
     pub unsafe fn try_read(&self) -> bool {
-        self.mutex.try_lock()
+        self.lock.lock();
+        let ok = (*self.state.get()).inc_readers();
+        self.lock.unlock();
+        return ok;
     }
 
     #[inline]
     pub unsafe fn write(&self) {
-        self.mutex.lock();
+        self.lock.lock();
+        while !(*self.state.get()).inc_writers() {
+            self.cond.wait(&self.lock);
+        }
+        self.lock.unlock();
     }
 
     #[inline]
     pub unsafe fn try_write(&self) -> bool {
-        self.mutex.try_lock()
+        self.lock.lock();
+        let ok = (*self.state.get()).inc_writers();
+        self.lock.unlock();
+        return ok;
     }
 
     #[inline]
     pub unsafe fn read_unlock(&self) {
-        self.mutex.unlock();
+        self.lock.lock();
+        let notify = (*self.state.get()).dec_readers();
+        self.lock.unlock();
+        if notify {
+            // FIXME: should only wake up one of these some of the time
+            self.cond.notify_all();
+        }
     }
 
     #[inline]
     pub unsafe fn write_unlock(&self) {
-        self.mutex.unlock();
+        self.lock.lock();
+        (*self.state.get()).dec_writers();
+        self.lock.unlock();
+        // FIXME: should only wake up one of these some of the time
+        self.cond.notify_all();
     }
 
     #[inline]
     pub unsafe fn destroy(&self) {
-        self.mutex.destroy();
+        self.lock.destroy();
+        self.cond.destroy();
+    }
+}
+
+impl State {
+    fn inc_readers(&mut self) -> bool {
+        match *self {
+            State::Unlocked => {
+                *self = State::Reading(1);
+                true
+            }
+            State::Reading(ref mut cnt) => {
+                *cnt += 1;
+                true
+            }
+            State::Writing => false,
+        }
+    }
+
+    fn inc_writers(&mut self) -> bool {
+        match *self {
+            State::Unlocked => {
+                *self = State::Writing;
+                true
+            }
+            State::Reading(_) | State::Writing => false,
+        }
+    }
+
+    fn dec_readers(&mut self) -> bool {
+        let zero = match *self {
+            State::Reading(ref mut cnt) => {
+                *cnt -= 1;
+                *cnt == 0
+            }
+            State::Unlocked | State::Writing => invalid(),
+        };
+        if zero {
+            *self = State::Unlocked;
+        }
+        zero
     }
+
+    fn dec_writers(&mut self) {
+        match *self {
+            State::Writing => {}
+            State::Unlocked | State::Reading(_) => invalid(),
+        }
+        *self = State::Unlocked;
+    }
+}
+
+fn invalid() -> ! {
+    panic!("inconsistent rwlock");
 }
diff --git a/src/test/mir-opt/const_prop/boolean_identities.rs b/src/test/mir-opt/const_prop/boolean_identities.rs
new file mode 100644
index 0000000000000..4e09acbaa53b4
--- /dev/null
+++ b/src/test/mir-opt/const_prop/boolean_identities.rs
@@ -0,0 +1,10 @@
+// compile-flags: -O -Zmir-opt-level=3
+
+// EMIT_MIR rustc.test.ConstProp.diff
+pub fn test(x: bool, y: bool) -> bool {
+    (y | true) & (x & false)
+}
+
+fn main() {
+    test(true, false);
+}
diff --git a/src/test/mir-opt/const_prop/boolean_identities/rustc.test.ConstProp.diff b/src/test/mir-opt/const_prop/boolean_identities/rustc.test.ConstProp.diff
new file mode 100644
index 0000000000000..b8f0ad4d434cb
--- /dev/null
+++ b/src/test/mir-opt/const_prop/boolean_identities/rustc.test.ConstProp.diff
@@ -0,0 +1,53 @@
+- // MIR for `test` before ConstProp
++ // MIR for `test` after ConstProp
+  
+  fn test(_1: bool, _2: bool) -> bool {
+      debug x => _1;                       // in scope 0 at $DIR/boolean_identities.rs:4:13: 4:14
+      debug y => _2;                       // in scope 0 at $DIR/boolean_identities.rs:4:22: 4:23
+      let mut _0: bool;                    // return place in scope 0 at $DIR/boolean_identities.rs:4:34: 4:38
+      let mut _3: bool;                    // in scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
+      let mut _4: bool;                    // in scope 0 at $DIR/boolean_identities.rs:5:6: 5:7
+      let mut _5: bool;                    // in scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
+      let mut _6: bool;                    // in scope 0 at $DIR/boolean_identities.rs:5:19: 5:20
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
+          StorageLive(_4);                 // scope 0 at $DIR/boolean_identities.rs:5:6: 5:7
+          _4 = _2;                         // scope 0 at $DIR/boolean_identities.rs:5:6: 5:7
+-         _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
++         _3 = const true;                 // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+-                                          // + span: $DIR/boolean_identities.rs:5:10: 5:14
++                                          // + span: $DIR/boolean_identities.rs:5:5: 5:15
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          StorageDead(_4);                 // scope 0 at $DIR/boolean_identities.rs:5:14: 5:15
+          StorageLive(_5);                 // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
+          StorageLive(_6);                 // scope 0 at $DIR/boolean_identities.rs:5:19: 5:20
+          _6 = _1;                         // scope 0 at $DIR/boolean_identities.rs:5:19: 5:20
+-         _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
++         _5 = const false;                // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+-                                          // + span: $DIR/boolean_identities.rs:5:23: 5:28
++                                          // + span: $DIR/boolean_identities.rs:5:18: 5:29
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          StorageDead(_6);                 // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29
+-         _0 = BitAnd(move _3, move _5);   // scope 0 at $DIR/boolean_identities.rs:5:5: 5:29
++         _0 = const false;                // scope 0 at $DIR/boolean_identities.rs:5:5: 5:29
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
++                                          // mir::Constant
++                                          // + span: $DIR/boolean_identities.rs:5:5: 5:29
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          StorageDead(_5);                 // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29
+          StorageDead(_3);                 // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29
+          return;                          // scope 0 at $DIR/boolean_identities.rs:6:2: 6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/mult_by_zero.rs b/src/test/mir-opt/const_prop/mult_by_zero.rs
new file mode 100644
index 0000000000000..f40faee3110ae
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mult_by_zero.rs
@@ -0,0 +1,10 @@
+// compile-flags: -O -Zmir-opt-level=3
+
+// EMIT_MIR rustc.test.ConstProp.diff
+fn test(x : i32) -> i32 {
+  x * 0
+}
+
+fn main() {
+    test(10);
+}
diff --git a/src/test/mir-opt/const_prop/mult_by_zero/rustc.test.ConstProp.diff b/src/test/mir-opt/const_prop/mult_by_zero/rustc.test.ConstProp.diff
new file mode 100644
index 0000000000000..7b36669bf15b2
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mult_by_zero/rustc.test.ConstProp.diff
@@ -0,0 +1,25 @@
+- // MIR for `test` before ConstProp
++ // MIR for `test` after ConstProp
+  
+  fn test(_1: i32) -> i32 {
+      debug x => _1;                       // in scope 0 at $DIR/mult_by_zero.rs:4:9: 4:10
+      let mut _0: i32;                     // return place in scope 0 at $DIR/mult_by_zero.rs:4:21: 4:24
+      let mut _2: i32;                     // in scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4
+          _2 = _1;                         // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4
+-         _0 = Mul(move _2, const 0_i32);  // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:8
++         _0 = const 0_i32;                // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:8
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+-                                          // + span: $DIR/mult_by_zero.rs:5:7: 5:8
++                                          // + span: $DIR/mult_by_zero.rs:5:3: 5:8
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+          StorageDead(_2);                 // scope 0 at $DIR/mult_by_zero.rs:5:7: 5:8
+          return;                          // scope 0 at $DIR/mult_by_zero.rs:6:2: 6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/match-arm-scopes.rs b/src/test/mir-opt/match-arm-scopes.rs
index 0e30a15671528..2c5816c51e3e2 100644
--- a/src/test/mir-opt/match-arm-scopes.rs
+++ b/src/test/mir-opt/match-arm-scopes.rs
@@ -9,8 +9,7 @@
 //   all of the bindings for that scope.
 // * No drop flags are used.
 
-// EMIT_MIR rustc.complicated_match.SimplifyCfg-initial.after.mir
-// EMIT_MIR rustc.complicated_match.ElaborateDrops.after.mir
+// EMIT_MIR rustc.complicated_match SimplifyCfg-initial.after ElaborateDrops.after
 fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 {
     match items {
         (false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1,
diff --git a/src/test/mir-opt/match-arm-scopes/rustc.complicated_match.ElaborateDrops.after.mir b/src/test/mir-opt/match-arm-scopes/rustc.complicated_match.ElaborateDrops.after.mir
deleted file mode 100644
index df6a247bb5ff6..0000000000000
--- a/src/test/mir-opt/match-arm-scopes/rustc.complicated_match.ElaborateDrops.after.mir
+++ /dev/null
@@ -1,235 +0,0 @@
-// MIR for `complicated_match` after ElaborateDrops
-
-fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
-    debug cond => _1;                    // in scope 0 at $DIR/match-arm-scopes.rs:14:22: 14:26
-    debug items => _2;                   // in scope 0 at $DIR/match-arm-scopes.rs:14:34: 14:39
-    let mut _0: i32;                     // return place in scope 0 at $DIR/match-arm-scopes.rs:14:66: 14:69
-    let mut _3: &bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
-    let mut _4: &bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
-    let _5: bool;                        // in scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-    let _6: &bool;                       // in scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-    let _7: std::string::String;         // in scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-    let _8: &std::string::String;        // in scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-    let mut _9: bool;                    // in scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    let mut _10: bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-    let mut _11: !;                      // in scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
-    let mut _12: bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    let mut _13: bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-    let mut _14: !;                      // in scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
-    let _15: bool;                       // in scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
-    let _16: std::string::String;        // in scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
-    scope 1 {
-        debug a => _5;                   // in scope 1 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        debug a => _6;                   // in scope 1 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        debug s => _7;                   // in scope 1 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        debug s => _8;                   // in scope 1 at $DIR/match-arm-scopes.rs:16:20: 16:21
-    }
-    scope 2 {
-        debug b => _15;                  // in scope 2 at $DIR/match-arm-scopes.rs:17:16: 17:17
-        debug t => _16;                  // in scope 2 at $DIR/match-arm-scopes.rs:17:19: 17:20
-    }
-
-    bb0: {
-        switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:15
-    }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/match-arm-scopes.rs:14:1: 19:2
-    }
-
-    bb2: {
-        switchInt((_2.1: bool)) -> [false: bb14, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:16:29: 16:34
-    }
-
-    bb3: {
-        switchInt((_2.0: bool)) -> [false: bb4, otherwise: bb21]; // scope 0 at $DIR/match-arm-scopes.rs:17:10: 17:14
-    }
-
-    bb4: {
-        StorageLive(_15);                // scope 0 at $DIR/match-arm-scopes.rs:17:32: 17:33
-        _15 = (_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:17:32: 17:33
-        StorageLive(_16);                // scope 0 at $DIR/match-arm-scopes.rs:17:35: 17:36
-        _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:17:35: 17:36
-        goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb5: {
-        _0 = const 1_i32;                // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
-                                         // ty::Const
-                                         // + ty: i32
-                                         // + val: Value(Scalar(0x00000001))
-                                         // mir::Constant
-                                         // + span: $DIR/match-arm-scopes.rs:16:77: 16:78
-                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
-        drop(_7) -> [return: bb19, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-    }
-
-    bb6: {
-        StorageLive(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        _6 = &(_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        StorageLive(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        StorageLive(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-        StorageLive(_10);                // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        _10 = _1;                        // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        switchInt(_10) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb7: {
-        _9 = (*_6);                      // scope 0 at $DIR/match-arm-scopes.rs:16:70: 16:71
-        StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        switchInt(move _9) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb8: {
-        _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
-                                         // ty::Const
-                                         // + ty: i32
-                                         // + val: Value(Scalar(0x00000003))
-                                         // mir::Constant
-                                         // + span: $DIR/match-arm-scopes.rs:16:59: 16:60
-                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
-        StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        goto -> bb11;                    // scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
-    }
-
-    bb9: {
-        return;                          // scope 0 at $DIR/match-arm-scopes.rs:19:2: 19:2
-    }
-
-    bb10 (cleanup): {
-        goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb11: {
-        drop(_2) -> [return: bb9, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb12: {
-        StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageLive(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        _5 = (_2.1: bool);               // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        StorageLive(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        goto -> bb5;                     // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb13: {
-        StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        goto -> bb2;                     // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb14: {
-        StorageLive(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
-        _6 = &(_2.0: bool);              // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
-        StorageLive(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
-        _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
-        StorageLive(_12);                // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-        StorageLive(_13);                // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        _13 = _1;                        // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        switchInt(_13) -> [false: bb15, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb15: {
-        _12 = (*_6);                     // scope 0 at $DIR/match-arm-scopes.rs:16:70: 16:71
-        StorageDead(_13);                // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        switchInt(move _12) -> [false: bb18, otherwise: bb17]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb16: {
-        _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
-                                         // ty::Const
-                                         // + ty: i32
-                                         // + val: Value(Scalar(0x00000003))
-                                         // mir::Constant
-                                         // + span: $DIR/match-arm-scopes.rs:16:59: 16:60
-                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
-        StorageDead(_13);                // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        goto -> bb11;                    // scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
-    }
-
-    bb17: {
-        StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageLive(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
-        _5 = (_2.0: bool);               // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
-        StorageLive(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
-        _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
-        goto -> bb5;                     // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb18: {
-        StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        goto -> bb3;                     // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb19: {
-        StorageDead(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb20: {
-        _0 = const 2_i32;                // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
-                                         // ty::Const
-                                         // + ty: i32
-                                         // + val: Value(Scalar(0x00000002))
-                                         // mir::Constant
-                                         // + span: $DIR/match-arm-scopes.rs:17:41: 17:42
-                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
-        drop(_16) -> [return: bb22, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
-    }
-
-    bb21: {
-        StorageLive(_15);                // scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
-        _15 = (_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
-        StorageLive(_16);                // scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
-        _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
-        goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb22: {
-        StorageDead(_16);                // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
-        StorageDead(_15);                // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
-        goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb23: {
-        goto -> bb29;                    // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb24 (cleanup): {
-        goto -> bb1;                     // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb25 (cleanup): {
-        goto -> bb24;                    // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb26: {
-        goto -> bb9;                     // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb27 (cleanup): {
-        goto -> bb1;                     // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb28 (cleanup): {
-        goto -> bb27;                    // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb29: {
-        goto -> bb26;                    // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-}
diff --git a/src/test/mir-opt/match-arm-scopes/rustc.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/src/test/mir-opt/match-arm-scopes/rustc.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
new file mode 100644
index 0000000000000..58847e1bceee6
--- /dev/null
+++ b/src/test/mir-opt/match-arm-scopes/rustc.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -0,0 +1,313 @@
+- // MIR for `complicated_match` after SimplifyCfg-initial
++ // MIR for `complicated_match` after ElaborateDrops
+  
+  fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
+      debug cond => _1;                    // in scope 0 at $DIR/match-arm-scopes.rs:13:22: 13:26
+      debug items => _2;                   // in scope 0 at $DIR/match-arm-scopes.rs:13:34: 13:39
+      let mut _0: i32;                     // return place in scope 0 at $DIR/match-arm-scopes.rs:13:66: 13:69
+      let mut _3: &bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+      let mut _4: &bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+      let _5: bool;                        // in scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+      let _6: &bool;                       // in scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+      let _7: std::string::String;         // in scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+      let _8: &std::string::String;        // in scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+      let mut _9: bool;                    // in scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+      let mut _10: bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+      let mut _11: !;                      // in scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
+      let mut _12: bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+      let mut _13: bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+      let mut _14: !;                      // in scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
+      let _15: bool;                       // in scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17
+      let _16: std::string::String;        // in scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20
+      scope 1 {
+          debug a => _5;                   // in scope 1 at $DIR/match-arm-scopes.rs:15:17: 15:18
+          debug a => _6;                   // in scope 1 at $DIR/match-arm-scopes.rs:15:17: 15:18
+          debug s => _7;                   // in scope 1 at $DIR/match-arm-scopes.rs:15:20: 15:21
+          debug s => _8;                   // in scope 1 at $DIR/match-arm-scopes.rs:15:20: 15:21
+      }
+      scope 2 {
+          debug b => _15;                  // in scope 2 at $DIR/match-arm-scopes.rs:16:16: 16:17
+          debug t => _16;                  // in scope 2 at $DIR/match-arm-scopes.rs:16:19: 16:20
+      }
+  
+      bb0: {
+-         FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+-         switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
++         switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/match-arm-scopes.rs:13:1: 18:2
+      }
+  
+      bb2: {
+-         falseEdge -> [real: bb9, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:15:9: 15:22
++         switchInt((_2.1: bool)) -> [false: bb14, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:29: 15:34
+      }
+  
+      bb3: {
+-         switchInt((_2.1: bool)) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:15:29: 15:34
++         switchInt((_2.0: bool)) -> [false: bb4, otherwise: bb21]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:14
+      }
+  
+      bb4: {
+-         falseEdge -> [real: bb18, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:15:25: 15:38
+-     }
+- 
+-     bb5: {
+-         switchInt((_2.0: bool)) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:14
+-     }
+- 
+-     bb6: {
+-         falseEdge -> [real: bb26, imaginary: bb7]; // scope 0 at $DIR/match-arm-scopes.rs:16:9: 16:21
+-     }
+- 
+-     bb7: {
+          StorageLive(_15);                // scope 0 at $DIR/match-arm-scopes.rs:16:32: 16:33
+          _15 = (_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:16:32: 16:33
+          StorageLive(_16);                // scope 0 at $DIR/match-arm-scopes.rs:16:35: 16:36
+          _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:35: 16:36
+-         goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+      }
+  
+-     bb8: {
++     bb5: {
+          _0 = const 1_i32;                // scope 1 at $DIR/match-arm-scopes.rs:15:77: 15:78
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/match-arm-scopes.rs:15:77: 15:78
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+-         drop(_7) -> [return: bb24, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
++         drop(_7) -> [return: bb19, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+      }
+  
+-     bb9: {
++     bb6: {
+          StorageLive(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+          _6 = &(_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+          StorageLive(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+          _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+-         _3 = &shallow (_2.0: bool);      // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+-         _4 = &shallow (_2.1: bool);      // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+          StorageLive(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+          StorageLive(_10);                // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+          _10 = _1;                        // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+-         FakeRead(ForMatchedPlace, _10);  // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+-         switchInt(_10) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         switchInt(_10) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+      }
+  
+-     bb10: {
+-         falseEdge -> [real: bb12, imaginary: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-     }
+- 
+-     bb11: {
++     bb7: {
+          _9 = (*_6);                      // scope 0 at $DIR/match-arm-scopes.rs:15:70: 15:71
+          StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+-         switchInt(move _9) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         switchInt(move _9) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+      }
+  
+-     bb12: {
++     bb8: {
+          _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000003))
+                                           // mir::Constant
+                                           // + span: $DIR/match-arm-scopes.rs:15:59: 15:60
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
+          StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+          StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         goto -> bb15;                    // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
++         goto -> bb11;                    // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
+      }
+  
+-     bb13: {
++     bb9: {
+          return;                          // scope 0 at $DIR/match-arm-scopes.rs:18:2: 18:2
+      }
+  
+-     bb14 (cleanup): {
+-         drop(_2) -> bb1;                 // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     bb10 (cleanup): {
++         goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+      }
+  
+-     bb15: {
+-         drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     bb11: {
++         drop(_2) -> [return: bb9, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+      }
+  
+-     bb16: {
++     bb12: {
+          StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         FakeRead(ForMatchGuard, _3);     // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+-         FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+-         FakeRead(ForGuardBinding, _6);   // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+-         FakeRead(ForGuardBinding, _8);   // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+          StorageLive(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+          _5 = (_2.1: bool);               // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+          StorageLive(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+          _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+-         goto -> bb8;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb5;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+      }
+  
+-     bb17: {
++     bb13: {
+          StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         falseEdge -> [real: bb3, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         goto -> bb2;                     // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+      }
+  
+-     bb18: {
++     bb14: {
+          StorageLive(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
+          _6 = &(_2.0: bool);              // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
+          StorageLive(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
+          _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
+-         _3 = &shallow (_2.0: bool);      // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+-         _4 = &shallow (_2.1: bool);      // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+          StorageLive(_12);                // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+          StorageLive(_13);                // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+          _13 = _1;                        // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+-         FakeRead(ForMatchedPlace, _13);  // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+-         switchInt(_13) -> [false: bb20, otherwise: bb19]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         switchInt(_13) -> [false: bb15, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+      }
+  
+-     bb19: {
+-         falseEdge -> [real: bb21, imaginary: bb20]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-     }
+- 
+-     bb20: {
++     bb15: {
+          _12 = (*_6);                     // scope 0 at $DIR/match-arm-scopes.rs:15:70: 15:71
+          StorageDead(_13);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+-         switchInt(move _12) -> [false: bb23, otherwise: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         switchInt(move _12) -> [false: bb18, otherwise: bb17]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+      }
+  
+-     bb21: {
++     bb16: {
+          _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000003))
+                                           // mir::Constant
+                                           // + span: $DIR/match-arm-scopes.rs:15:59: 15:60
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
+          StorageDead(_13);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+          StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         goto -> bb15;                    // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
++         goto -> bb11;                    // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
+      }
+  
+-     bb22: {
++     bb17: {
+          StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         FakeRead(ForMatchGuard, _3);     // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+-         FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+-         FakeRead(ForGuardBinding, _6);   // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+-         FakeRead(ForGuardBinding, _8);   // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+          StorageLive(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
+          _5 = (_2.0: bool);               // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
+          StorageLive(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
+          _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
+-         goto -> bb8;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb5;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+      }
+  
+-     bb23: {
++     bb18: {
+          StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         falseEdge -> [real: bb5, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         goto -> bb3;                     // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+      }
+  
+-     bb24: {
++     bb19: {
+          StorageDead(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         goto -> bb28;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+      }
+  
+-     bb25: {
++     bb20: {
+          _0 = const 2_i32;                // scope 2 at $DIR/match-arm-scopes.rs:16:41: 16:42
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000002))
+                                           // mir::Constant
+                                           // + span: $DIR/match-arm-scopes.rs:16:41: 16:42
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
+-         drop(_16) -> [return: bb27, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
++         drop(_16) -> [return: bb22, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
+      }
+  
+-     bb26: {
++     bb21: {
+          StorageLive(_15);                // scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17
+          _15 = (_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17
+          StorageLive(_16);                // scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20
+          _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20
+-         goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+      }
+  
+-     bb27: {
++     bb22: {
+          StorageDead(_16);                // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
+          StorageDead(_15);                // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
+-         goto -> bb28;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+      }
+  
+-     bb28: {
+-         drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     bb23: {
++         goto -> bb29;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     }
++ 
++     bb24 (cleanup): {
++         goto -> bb1;                     // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     }
++ 
++     bb25 (cleanup): {
++         goto -> bb24;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     }
++ 
++     bb26: {
++         goto -> bb9;                     // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     }
++ 
++     bb27 (cleanup): {
++         goto -> bb1;                     // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     }
++ 
++     bb28 (cleanup): {
++         goto -> bb27;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     }
++ 
++     bb29: {
++         goto -> bb26;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/match-arm-scopes/rustc.complicated_match.SimplifyCfg-initial.after.mir b/src/test/mir-opt/match-arm-scopes/rustc.complicated_match.SimplifyCfg-initial.after.mir
deleted file mode 100644
index dadbc3668cb29..0000000000000
--- a/src/test/mir-opt/match-arm-scopes/rustc.complicated_match.SimplifyCfg-initial.after.mir
+++ /dev/null
@@ -1,246 +0,0 @@
-// MIR for `complicated_match` after SimplifyCfg-initial
-
-fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
-    debug cond => _1;                    // in scope 0 at $DIR/match-arm-scopes.rs:14:22: 14:26
-    debug items => _2;                   // in scope 0 at $DIR/match-arm-scopes.rs:14:34: 14:39
-    let mut _0: i32;                     // return place in scope 0 at $DIR/match-arm-scopes.rs:14:66: 14:69
-    let mut _3: &bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
-    let mut _4: &bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
-    let _5: bool;                        // in scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-    let _6: &bool;                       // in scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-    let _7: std::string::String;         // in scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-    let _8: &std::string::String;        // in scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-    let mut _9: bool;                    // in scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    let mut _10: bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-    let mut _11: !;                      // in scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
-    let mut _12: bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    let mut _13: bool;                   // in scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-    let mut _14: !;                      // in scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
-    let _15: bool;                       // in scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
-    let _16: std::string::String;        // in scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
-    scope 1 {
-        debug a => _5;                   // in scope 1 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        debug a => _6;                   // in scope 1 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        debug s => _7;                   // in scope 1 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        debug s => _8;                   // in scope 1 at $DIR/match-arm-scopes.rs:16:20: 16:21
-    }
-    scope 2 {
-        debug b => _15;                  // in scope 2 at $DIR/match-arm-scopes.rs:17:16: 17:17
-        debug t => _16;                  // in scope 2 at $DIR/match-arm-scopes.rs:17:19: 17:20
-    }
-
-    bb0: {
-        FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
-        switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:15
-    }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/match-arm-scopes.rs:14:1: 19:2
-    }
-
-    bb2: {
-        falseEdge -> [real: bb9, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:16:9: 16:22
-    }
-
-    bb3: {
-        switchInt((_2.1: bool)) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:16:29: 16:34
-    }
-
-    bb4: {
-        falseEdge -> [real: bb18, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:16:25: 16:38
-    }
-
-    bb5: {
-        switchInt((_2.0: bool)) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:17:10: 17:14
-    }
-
-    bb6: {
-        falseEdge -> [real: bb26, imaginary: bb7]; // scope 0 at $DIR/match-arm-scopes.rs:17:9: 17:21
-    }
-
-    bb7: {
-        StorageLive(_15);                // scope 0 at $DIR/match-arm-scopes.rs:17:32: 17:33
-        _15 = (_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:17:32: 17:33
-        StorageLive(_16);                // scope 0 at $DIR/match-arm-scopes.rs:17:35: 17:36
-        _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:17:35: 17:36
-        goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb8: {
-        _0 = const 1_i32;                // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
-                                         // ty::Const
-                                         // + ty: i32
-                                         // + val: Value(Scalar(0x00000001))
-                                         // mir::Constant
-                                         // + span: $DIR/match-arm-scopes.rs:16:77: 16:78
-                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
-        drop(_7) -> [return: bb24, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-    }
-
-    bb9: {
-        StorageLive(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        _6 = &(_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        StorageLive(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        _3 = &shallow (_2.0: bool);      // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
-        _4 = &shallow (_2.1: bool);      // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
-        StorageLive(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-        StorageLive(_10);                // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        _10 = _1;                        // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        FakeRead(ForMatchedPlace, _10);  // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        switchInt(_10) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb10: {
-        falseEdge -> [real: bb12, imaginary: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb11: {
-        _9 = (*_6);                      // scope 0 at $DIR/match-arm-scopes.rs:16:70: 16:71
-        StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        switchInt(move _9) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb12: {
-        _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
-                                         // ty::Const
-                                         // + ty: i32
-                                         // + val: Value(Scalar(0x00000003))
-                                         // mir::Constant
-                                         // + span: $DIR/match-arm-scopes.rs:16:59: 16:60
-                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
-        StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        goto -> bb15;                    // scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
-    }
-
-    bb13: {
-        return;                          // scope 0 at $DIR/match-arm-scopes.rs:19:2: 19:2
-    }
-
-    bb14 (cleanup): {
-        drop(_2) -> bb1;                 // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb15: {
-        drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-
-    bb16: {
-        StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        FakeRead(ForMatchGuard, _3);     // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        FakeRead(ForGuardBinding, _6);   // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        FakeRead(ForGuardBinding, _8);   // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        StorageLive(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        _5 = (_2.1: bool);               // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
-        StorageLive(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
-        goto -> bb8;                     // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb17: {
-        StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        falseEdge -> [real: bb3, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb18: {
-        StorageLive(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
-        _6 = &(_2.0: bool);              // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
-        StorageLive(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
-        _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
-        _3 = &shallow (_2.0: bool);      // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
-        _4 = &shallow (_2.1: bool);      // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
-        StorageLive(_12);                // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-        StorageLive(_13);                // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        _13 = _1;                        // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        FakeRead(ForMatchedPlace, _13);  // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
-        switchInt(_13) -> [false: bb20, otherwise: bb19]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb19: {
-        falseEdge -> [real: bb21, imaginary: bb20]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb20: {
-        _12 = (*_6);                     // scope 0 at $DIR/match-arm-scopes.rs:16:70: 16:71
-        StorageDead(_13);                // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        switchInt(move _12) -> [false: bb23, otherwise: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb21: {
-        _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
-                                         // ty::Const
-                                         // + ty: i32
-                                         // + val: Value(Scalar(0x00000003))
-                                         // mir::Constant
-                                         // + span: $DIR/match-arm-scopes.rs:16:59: 16:60
-                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
-        StorageDead(_13);                // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        goto -> bb15;                    // scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
-    }
-
-    bb22: {
-        StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        FakeRead(ForMatchGuard, _3);     // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        FakeRead(ForGuardBinding, _6);   // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        FakeRead(ForGuardBinding, _8);   // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
-        StorageLive(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
-        _5 = (_2.0: bool);               // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
-        StorageLive(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
-        _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
-        goto -> bb8;                     // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb23: {
-        StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        falseEdge -> [real: bb5, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
-    }
-
-    bb24: {
-        StorageDead(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
-        goto -> bb28;                    // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb25: {
-        _0 = const 2_i32;                // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
-                                         // ty::Const
-                                         // + ty: i32
-                                         // + val: Value(Scalar(0x00000002))
-                                         // mir::Constant
-                                         // + span: $DIR/match-arm-scopes.rs:17:41: 17:42
-                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
-        drop(_16) -> [return: bb27, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
-    }
-
-    bb26: {
-        StorageLive(_15);                // scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
-        _15 = (_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
-        StorageLive(_16);                // scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
-        _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
-        goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb27: {
-        StorageDead(_16);                // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
-        StorageDead(_15);                // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
-        goto -> bb28;                    // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
-    }
-
-    bb28: {
-        drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
-    }
-}
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
index 2a983e426838c..795c5154f8155 100644
--- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
@@ -1,7 +1,7 @@
 // build-fail
 
 // Regression test for #66975
-#![warn(const_err)]
+#![warn(const_err, unconditional_panic)]
 #![feature(never_type)]
 
 struct PrintName<T>(T);
@@ -9,6 +9,7 @@ struct PrintName<T>(T);
 impl<T> PrintName<T> {
     const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
     //~^ WARN any use of this value will cause an error
+
 }
 
 fn f<T>() {
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
index d78e0da00f5e1..33e60dd7c9138 100644
--- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
@@ -9,11 +9,11 @@ LL |     const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
 note: the lint level is defined here
   --> $DIR/index-out-of-bounds-never-type.rs:4:9
    |
-LL | #![warn(const_err)]
+LL | #![warn(const_err, unconditional_panic)]
    |         ^^^^^^^^^
 
 error: erroneous constant encountered
-  --> $DIR/index-out-of-bounds-never-type.rs:15:13
+  --> $DIR/index-out-of-bounds-never-type.rs:16:13
    |
 LL |     let _ = PrintName::<T>::VOID;
    |             ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/error-codes/E0308-2.rs b/src/test/ui/error-codes/E0308-2.rs
new file mode 100644
index 0000000000000..157f992da9940
--- /dev/null
+++ b/src/test/ui/error-codes/E0308-2.rs
@@ -0,0 +1,12 @@
+trait DynEq {}
+
+impl<'a> PartialEq for &'a (dyn DynEq + 'static) {
+    fn eq(&self, _other: &Self) -> bool {
+        true
+    }
+}
+
+impl Eq for &dyn DynEq {} //~ ERROR E0308
+
+fn main() {
+}
diff --git a/src/test/ui/error-codes/E0308-2.stderr b/src/test/ui/error-codes/E0308-2.stderr
new file mode 100644
index 0000000000000..e7c5e4b42405f
--- /dev/null
+++ b/src/test/ui/error-codes/E0308-2.stderr
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/E0308-2.rs:9:6
+   |
+LL | impl Eq for &dyn DynEq {}
+   |      ^^ lifetime mismatch
+   |
+   = note: expected trait `std::cmp::PartialEq`
+              found trait `std::cmp::PartialEq`
+note: the lifetime `'_` as defined on the impl at 9:13...
+  --> $DIR/E0308-2.rs:9:13
+   |
+LL | impl Eq for &dyn DynEq {}
+   |             ^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index f09f7621aa170..21fb7673ce061 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3135,14 +3135,47 @@ impl<'test> TestCx<'test> {
         }
         for l in test_file_contents.lines() {
             if l.starts_with("// EMIT_MIR ") {
-                let test_name = l.trim_start_matches("// EMIT_MIR ");
-                let expected_file = test_dir.join(test_name);
-
-                let dumped_string = if test_name.ends_with(".diff") {
-                    let test_name = test_name.trim_end_matches(".diff");
-                    let before = format!("{}.before.mir", test_name);
-                    let after = format!("{}.after.mir", test_name);
-                    let before = self.get_mir_dump_dir().join(before);
+                let test_name = l.trim_start_matches("// EMIT_MIR ").trim();
+                let mut test_names = test_name.split(' ');
+                // sometimes we specify two files so that we get a diff between the two files
+                let test_name = test_names.next().unwrap();
+                let expected_file;
+                let from_file;
+                let to_file;
+
+                if test_name.ends_with(".diff") {
+                    let trimmed = test_name.trim_end_matches(".diff");
+                    let test_against = format!("{}.after.mir", trimmed);
+                    from_file = format!("{}.before.mir", trimmed);
+                    expected_file = test_name.to_string();
+                    assert!(
+                        test_names.next().is_none(),
+                        "two mir pass names specified for MIR diff"
+                    );
+                    to_file = Some(test_against);
+                } else if let Some(first_pass) = test_names.next() {
+                    let second_pass = test_names.next().unwrap();
+                    assert!(
+                        test_names.next().is_none(),
+                        "three mir pass names specified for MIR diff"
+                    );
+                    expected_file = format!("{}.{}-{}.diff", test_name, first_pass, second_pass);
+                    let second_file = format!("{}.{}.mir", test_name, second_pass);
+                    from_file = format!("{}.{}.mir", test_name, first_pass);
+                    to_file = Some(second_file);
+                } else {
+                    expected_file = test_name.to_string();
+                    from_file = test_name.to_string();
+                    assert!(
+                        test_names.next().is_none(),
+                        "two mir pass names specified for MIR dump"
+                    );
+                    to_file = None;
+                };
+                let expected_file = test_dir.join(expected_file);
+
+                let dumped_string = if let Some(after) = to_file {
+                    let before = self.get_mir_dump_dir().join(from_file);
                     let after = self.get_mir_dump_dir().join(after);
                     debug!(
                         "comparing the contents of: {} with {}",
@@ -3166,7 +3199,7 @@ impl<'test> TestCx<'test> {
                 } else {
                     let mut output_file = PathBuf::new();
                     output_file.push(self.get_mir_dump_dir());
-                    output_file.push(test_name);
+                    output_file.push(&from_file);
                     debug!(
                         "comparing the contents of: {} with {}",
                         output_file.display(),
@@ -3179,7 +3212,7 @@ impl<'test> TestCx<'test> {
                             output_file.parent().unwrap().display()
                         );
                     }
-                    self.check_mir_test_timestamp(test_name, &output_file);
+                    self.check_mir_test_timestamp(&from_file, &output_file);
                     let dumped_string = fs::read_to_string(&output_file).unwrap();
                     self.normalize_output(&dumped_string, &[])
                 };