Rollup merge of #72393 - Aaron1011:feature/rewrite-collect-tokens, r=petrochenkov

Rewrite `Parser::collect_tokens`

The previous implementation did not work when called on an opening
delimiter, or when called re-entrantly from the same `TokenCursor` stack
depth.

I'm not sure how to test this apart from https://github.com/rust-lang/rust/pull/72287
diff --git a/Cargo.lock b/Cargo.lock
index d81fd6e..6ce5458 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -213,6 +213,7 @@
  "lazy_static 1.4.0",
  "libc",
  "num_cpus",
+ "opener",
  "pretty_assertions",
  "serde",
  "serde_json",
@@ -2327,6 +2328,9 @@
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d6a04cb71e910d0034815600180f62a95bf6e67942d7ab52a166a68c7d7e9cd0"
+dependencies = [
+ "parking_lot 0.9.0",
+]
 
 [[package]]
 name = "opaque-debug"
@@ -3791,6 +3795,7 @@
  "libc",
  "log",
  "measureme",
+ "once_cell",
  "parking_lot 0.10.2",
  "rustc-hash",
  "rustc-rayon",
diff --git a/config.toml.example b/config.toml.example
index ffe907c..cf8fe4e 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -312,11 +312,11 @@
 
 # Whether or not debug assertions are enabled for the compiler and standard
 # library.
-#debug-assertions = false
+#debug-assertions = debug
 
 # Whether or not debug assertions are enabled for the standard library.
 # Overrides the `debug-assertions` option, if defined.
-#debug-assertions-std = false
+#debug-assertions-std = debug-assertions
 
 # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`.
 # `0` - no debug info
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index f7856f6..c4918d7 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -48,6 +48,7 @@
 lazy_static = "1.3.0"
 time = "0.1"
 ignore = "0.4.10"
+opener = "0.4"
 
 [target.'cfg(windows)'.dependencies.winapi]
 version = "0.3"
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 4bc81a7..5489b1b 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -503,7 +503,7 @@
             Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
             Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]),
             Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
-            Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
+            Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]),
             Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
             Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
             Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index c56114f..b399911 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -773,7 +773,8 @@
 
         // Ensure that `libLLVM.so` ends up in the newly build compiler directory,
         // so that it can be found when the newly built `rustc` is run.
-        dist::maybe_install_llvm_dylib(builder, target_compiler.host, &sysroot);
+        dist::maybe_install_llvm_runtime(builder, target_compiler.host, &sysroot);
+        dist::maybe_install_llvm_target(builder, target_compiler.host, &sysroot);
 
         // Link the compiler binary itself into place
         let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host);
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index c4bca4a..5e966d7 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -514,7 +514,7 @@
             // components like the llvm tools and LLD. LLD is included below and
             // tools/LLDB come later, so let's just throw it in the rustc
             // component for now.
-            maybe_install_llvm_dylib(builder, host, image);
+            maybe_install_llvm_runtime(builder, host, image);
 
             // Copy over lld if it's there
             if builder.config.lld_enabled {
@@ -2228,27 +2228,18 @@
     }
 }
 
-// Maybe add libLLVM.so to the lib-dir. It will only have been built if
-// LLVM tools are linked dynamically.
-//
-// We add this to both the libdir of the rustc binary itself (for it to load at
-// runtime) and also to the target directory so it can find it at link-time.
-//
-// Note: This function does no yet support Windows but we also don't support
-//       linking LLVM tools dynamically on Windows yet.
-pub fn maybe_install_llvm_dylib(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
+/// Maybe add libLLVM.so to the given destination lib-dir. It will only have
+/// been built if LLVM tools are linked dynamically.
+///
+/// Note: This function does not yet support Windows, but we also don't support
+///       linking LLVM tools dynamically on Windows yet.
+fn maybe_install_llvm(builder: &Builder<'_>, target: Interned<String>, dst_libdir: &Path) {
     let src_libdir = builder.llvm_out(target).join("lib");
-    let dst_libdir1 = sysroot.join("lib/rustlib").join(&*target).join("lib");
-    let dst_libdir2 =
-        sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
-    t!(fs::create_dir_all(&dst_libdir1));
-    t!(fs::create_dir_all(&dst_libdir2));
 
     if target.contains("apple-darwin") {
         let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
         if llvm_dylib_path.exists() {
-            builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
-            builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
+            builder.install(&llvm_dylib_path, dst_libdir, 0o644);
         }
         return;
     }
@@ -2262,11 +2253,23 @@
             panic!("dist: Error calling canonicalize path `{}`: {}", llvm_dylib_path.display(), e);
         });
 
-        builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
-        builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
+        builder.install(&llvm_dylib_path, dst_libdir, 0o644);
     }
 }
 
+/// Maybe add libLLVM.so to the target lib-dir for linking.
+pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
+    let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib");
+    maybe_install_llvm(builder, target, &dst_libdir);
+}
+
+/// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
+pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
+    let dst_libdir =
+        sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
+    maybe_install_llvm(builder, target, &dst_libdir);
+}
+
 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
 pub struct LlvmTools {
     pub target: Interned<String>,
@@ -2314,6 +2317,12 @@
             builder.install(&exe, &dst_bindir, 0o755);
         }
 
+        // Copy libLLVM.so to the target lib dir as well, so the RPATH like
+        // `$ORIGIN/../lib` can find it. It may also be used as a dependency
+        // of `rustc-dev` to support the inherited `-lLLVM` when using the
+        // compiler libraries.
+        maybe_install_llvm_target(builder, target, &image);
+
         // Prepare the overlay
         let overlay = tmp.join("llvm-tools-overlay");
         drop(fs::remove_dir_all(&overlay));
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 7eab92d..5c01c5e 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -70,6 +70,35 @@
     RustdocBook, "src/doc/rustdoc", "rustdoc";
 );
 
+fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {
+    if builder.config.dry_run || !builder.config.cmd.open() {
+        return;
+    }
+
+    let path = path.as_ref();
+    builder.info(&format!("Opening doc {}", path.display()));
+    if let Err(err) = opener::open(path) {
+        builder.info(&format!("{}\n", err));
+    }
+}
+
+// "src/libstd" -> ["src", "libstd"]
+//
+// Used for deciding whether a particular step is one requested by the user on
+// the `x.py doc` command line, which determines whether `--open` will open that
+// page.
+fn components_simplified(path: &PathBuf) -> Vec<&str> {
+    path.iter().map(|component| component.to_str().unwrap_or("???")).collect()
+}
+
+fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool {
+    builder
+        .paths
+        .iter()
+        .map(components_simplified)
+        .any(|requested| requested.iter().copied().eq(path.split("/")))
+}
+
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct UnstableBook {
     target: Interned<String>,
@@ -200,6 +229,12 @@
 
             invoke_rustdoc(builder, compiler, target, path);
         }
+
+        if is_explicit_request(builder, "src/doc/book") {
+            let out = builder.doc_out(target);
+            let index = out.join("book").join("index.html");
+            open(builder, &index);
+        }
     }
 }
 
@@ -338,6 +373,13 @@
             }
             builder.run(&mut cmd);
         }
+
+        // We open doc/index.html as the default if invoked as `x.py doc --open`
+        // with no particular explicit doc requested (e.g. src/libcore).
+        if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") {
+            let index = out.join("index.html");
+            open(builder, &index);
+        }
     }
 }
 
@@ -418,10 +460,25 @@
 
             builder.run(&mut cargo.into());
         };
-        for krate in &["alloc", "core", "std", "proc_macro", "test"] {
+        let krates = ["alloc", "core", "std", "proc_macro", "test"];
+        for krate in &krates {
             run_cargo_rustdoc_for(krate);
         }
         builder.cp_r(&my_out, &out);
+
+        // Look for src/libstd, src/libcore etc in the `x.py doc` arguments and
+        // open the corresponding rendered docs.
+        for path in builder.paths.iter().map(components_simplified) {
+            if path.get(0) == Some(&"src")
+                && path.get(1).map_or(false, |dir| dir.starts_with("lib"))
+            {
+                let requested_crate = &path[1][3..];
+                if krates.contains(&requested_crate) {
+                    let index = out.join(requested_crate).join("index.html");
+                    open(builder, &index);
+                }
+            }
+        }
     }
 }
 
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 646b9e0..cfaa43f 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -61,6 +61,7 @@
     },
     Doc {
         paths: Vec<PathBuf>,
+        open: bool,
     },
     Test {
         paths: Vec<PathBuf>,
@@ -248,6 +249,9 @@
             "bench" => {
                 opts.optmulti("", "test-args", "extra arguments", "ARGS");
             }
+            "doc" => {
+                opts.optflag("", "open", "open the docs in a browser");
+            }
             "clean" => {
                 opts.optflag("", "all", "clean all build artifacts");
             }
@@ -404,6 +408,7 @@
         ./x.py doc src/doc/book
         ./x.py doc src/doc/nomicon
         ./x.py doc src/doc/book src/libstd
+        ./x.py doc src/libstd --open
 
     If no arguments are passed then everything is documented:
 
@@ -479,7 +484,7 @@
                 },
             },
             "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
-            "doc" => Subcommand::Doc { paths },
+            "doc" => Subcommand::Doc { paths, open: matches.opt_present("open") },
             "clean" => {
                 if !paths.is_empty() {
                     println!("\nclean does not take a path argument\n");
@@ -613,6 +618,13 @@
             _ => None,
         }
     }
+
+    pub fn open(&self) -> bool {
+        match *self {
+            Subcommand::Doc { open, .. } => open,
+            _ => false,
+        }
+    }
 }
 
 fn split(s: &[String]) -> Vec<String> {
diff --git a/src/ci/scripts/install-msys2-packages.sh b/src/ci/scripts/install-msys2-packages.sh
index 8fefddd..ff7479c 100755
--- a/src/ci/scripts/install-msys2-packages.sh
+++ b/src/ci/scripts/install-msys2-packages.sh
@@ -6,17 +6,6 @@
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 if isWindows; then
-    # FIXME(mati865): temporary workaround until chocolatey updates their MSYS2
-    base_url='https://ci-mirrors.rust-lang.org/rustc/msys2-repo/msys/x86_64'
-    curl ${base_url}/libzstd-1.4.4-2-x86_64.pkg.tar.xz -o libzstd-1.4.4-2-x86_64.pkg.tar.xz
-    curl ${base_url}/pacman-5.2.1-6-x86_64.pkg.tar.xz -o pacman-5.2.1-6-x86_64.pkg.tar.xz
-    curl ${base_url}/zstd-1.4.4-2-x86_64.pkg.tar.xz -o zstd-1.4.4-2-x86_64.pkg.tar.xz
-    pacman -U --noconfirm libzstd-1.4.4-2-x86_64.pkg.tar.xz pacman-5.2.1-6-x86_64.pkg.tar.xz \
-        zstd-1.4.4-2-x86_64.pkg.tar.xz
-    rm libzstd-1.4.4-2-x86_64.pkg.tar.xz pacman-5.2.1-6-x86_64.pkg.tar.xz \
-        zstd-1.4.4-2-x86_64.pkg.tar.xz
-    pacman -Sy
-
     pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar \
         binutils
 
diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh
index b94eb5f..3c3b500 100755
--- a/src/ci/scripts/install-msys2.sh
+++ b/src/ci/scripts/install-msys2.sh
@@ -17,9 +17,8 @@
         msys2.nupkg
     curl -sSL https://packages.chocolatey.org/chocolatey-core.extension.1.3.5.1.nupkg > \
         chocolatey-core.extension.nupkg
-    # FIXME(mati865): remove `/NoUpdate` once chocolatey updates MSYS2
     choco install -s . msys2 \
-        --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath /NoUpdate" -y --no-progress
+        --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress
     rm msys2.nupkg chocolatey-core.extension.nupkg
     mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}"
     ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin"
diff --git a/src/libcore/future/into_future.rs b/src/libcore/future/into_future.rs
new file mode 100644
index 0000000..4020c25
--- /dev/null
+++ b/src/libcore/future/into_future.rs
@@ -0,0 +1,27 @@
+use crate::future::Future;
+
+/// Conversion into a `Future`.
+#[unstable(feature = "into_future", issue = "67644")]
+pub trait IntoFuture {
+    /// The output that the future will produce on completion.
+    #[unstable(feature = "into_future", issue = "67644")]
+    type Output;
+
+    /// Which kind of future are we turning this into?
+    #[unstable(feature = "into_future", issue = "67644")]
+    type Future: Future<Output = Self::Output>;
+
+    /// Creates a future from a value.
+    #[unstable(feature = "into_future", issue = "67644")]
+    fn into_future(self) -> Self::Future;
+}
+
+#[unstable(feature = "into_future", issue = "67644")]
+impl<F: Future> IntoFuture for F {
+    type Output = F::Output;
+    type Future = F;
+
+    fn into_future(self) -> Self::Future {
+        self
+    }
+}
diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs
index b5a1029..6f6009b 100644
--- a/src/libcore/future/mod.rs
+++ b/src/libcore/future/mod.rs
@@ -10,12 +10,16 @@
 };
 
 mod future;
+mod into_future;
 mod pending;
 mod ready;
 
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub use self::future::Future;
 
+#[unstable(feature = "into_future", issue = "67644")]
+pub use into_future::IntoFuture;
+
 #[unstable(feature = "future_readiness_fns", issue = "70921")]
 pub use pending::{pending, Pending};
 #[unstable(feature = "future_readiness_fns", issue = "70921")]
diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs
index f7ea7eb..01c9744 100644
--- a/src/libcore/mem/maybe_uninit.rs
+++ b/src/libcore/mem/maybe_uninit.rs
@@ -20,9 +20,9 @@
 /// # #![allow(invalid_value)]
 /// use std::mem::{self, MaybeUninit};
 ///
-/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior!
+/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! ⚠️
 /// // The equivalent code with `MaybeUninit<&i32>`:
-/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior!
+/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior! ⚠️
 /// ```
 ///
 /// This is exploited by the compiler for various optimizations, such as eliding
@@ -35,9 +35,9 @@
 /// # #![allow(invalid_value)]
 /// use std::mem::{self, MaybeUninit};
 ///
-/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior!
+/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! ⚠️
 /// // The equivalent code with `MaybeUninit<bool>`:
-/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior!
+/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️
 /// ```
 ///
 /// Moreover, uninitialized memory is special in that the compiler knows that
@@ -49,9 +49,9 @@
 /// # #![allow(invalid_value)]
 /// use std::mem::{self, MaybeUninit};
 ///
-/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior!
+/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! ⚠️
 /// // The equivalent code with `MaybeUninit<i32>`:
-/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior!
+/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️
 /// ```
 /// (Notice that the rules around uninitialized integers are not finalized yet, but
 /// until they are, it is advisable to avoid them.)
@@ -348,7 +348,7 @@
     /// let x = MaybeUninit::<(u8, NotZero)>::zeroed();
     /// let x = unsafe { x.assume_init() };
     /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant.
-    /// // This is undefined behavior.
+    /// // This is undefined behavior. ⚠️
     /// ```
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline]
@@ -400,7 +400,7 @@
     ///
     /// let x = MaybeUninit::<Vec<u32>>::uninit();
     /// let x_vec = unsafe { &*x.as_ptr() };
-    /// // We have created a reference to an uninitialized vector! This is undefined behavior.
+    /// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️
     /// ```
     ///
     /// (Notice that the rules around references to uninitialized data are not finalized yet, but
@@ -437,7 +437,7 @@
     ///
     /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
     /// let x_vec = unsafe { &mut *x.as_mut_ptr() };
-    /// // We have created a reference to an uninitialized vector! This is undefined behavior.
+    /// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️
     /// ```
     ///
     /// (Notice that the rules around references to uninitialized data are not finalized yet, but
@@ -489,7 +489,7 @@
     ///
     /// let x = MaybeUninit::<Vec<u32>>::uninit();
     /// let x_init = unsafe { x.assume_init() };
-    /// // `x` had not been initialized yet, so this last line caused undefined behavior.
+    /// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️
     /// ```
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
@@ -553,7 +553,7 @@
     /// x.write(Some(vec![0,1,2]));
     /// let x1 = unsafe { x.read() };
     /// let x2 = unsafe { x.read() };
-    /// // We now created two copies of the same vector, leading to a double-free when
+    /// // We now created two copies of the same vector, leading to a double-free ⚠️ when
     /// // they both get dropped!
     /// ```
     #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
@@ -603,7 +603,7 @@
     ///
     /// let x = MaybeUninit::<Vec<u32>>::uninit();
     /// let x_vec: &Vec<u32> = unsafe { x.get_ref() };
-    /// // We have created a reference to an uninitialized vector! This is undefined behavior.
+    /// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️
     /// ```
     ///
     /// ```rust,no_run
@@ -686,7 +686,7 @@
     /// unsafe {
     ///     *b.get_mut() = true;
     ///     // We have created a (mutable) reference to an uninitialized `bool`!
-    ///     // This is undefined behavior.
+    ///     // This is undefined behavior. ⚠️
     /// }
     /// ```
     ///
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
index 774ecd9..6f5bf7a 100644
--- a/src/libcore/pin.rs
+++ b/src/libcore/pin.rs
@@ -139,10 +139,12 @@
 //! otherwise invalidating the memory used to store the data is restricted, too.
 //! Concretely, for pinned data you have to maintain the invariant
 //! that *its memory will not get invalidated or repurposed from the moment it gets pinned until
-//! when [`drop`] is called*. Memory can be invalidated by deallocation, but also by
+//! when [`drop`] is called*.  Only once [`drop`] returns or panics, the memory may be reused.
+//!
+//! Memory can be "invalidated" by deallocation, but also by
 //! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements
 //! off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without
-//! calling the destructor first.
+//! calling the destructor first. None of this is allowed for pinned data without calling [`drop`].
 //!
 //! This is exactly the kind of guarantee that the intrusive linked list from the previous
 //! section needs to function correctly.
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 9582ac3..b5ce165 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -5740,7 +5740,8 @@
 ///   and it must be properly aligned. This means in particular:
 ///
 ///     * The entire memory range of this slice must be contained within a single allocated object!
-///       Slices can never span across multiple allocated objects.
+///       Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
+///       for an example incorrectly not taking this into account.
 ///     * `data` must be non-null and aligned even for zero-length slices. One
 ///       reason for this is that enum layout optimizations may rely on references
 ///       (including slices of any length) being aligned and non-null to distinguish
@@ -5773,6 +5774,34 @@
 /// assert_eq!(slice[0], 42);
 /// ```
 ///
+/// ### Incorrect usage
+///
+/// The following `join_slices` function is **unsound** ⚠️
+///
+/// ```rust,no_run
+/// use std::slice;
+///
+/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
+///     let fst_end = fst.as_ptr().wrapping_add(fst.len());
+///     let snd_start = snd.as_ptr();
+///     assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
+///     unsafe {
+///         // The assertion above ensures `fst` and `snd` are contiguous, but they might
+///         // still be contained within _different allocated objects_, in which case
+///         // creating this slice is undefined behavior.
+///         slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
+///     }
+/// }
+///
+/// fn main() {
+///     // `a` and `b` are different allocated objects...
+///     let a = 42;
+///     let b = 27;
+///     // ... which may nevertheless be laid out contiguously in memory: | a | b |
+///     let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
+/// }
+/// ```
+///
 /// [valid]: ../../std/ptr/index.html#safety
 /// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling
 /// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index f11401b..2d5bd7e 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -39,6 +39,7 @@
 #[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
 pub use diagnostic::{Diagnostic, Level, MultiSpan};
 
+use std::cmp::Ordering;
 use std::ops::{Bound, RangeBounds};
 use std::path::PathBuf;
 use std::str::FromStr;
@@ -420,6 +421,20 @@
 #[unstable(feature = "proc_macro_span", issue = "54725")]
 impl !Sync for LineColumn {}
 
+#[unstable(feature = "proc_macro_span", issue = "54725")]
+impl Ord for LineColumn {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.line.cmp(&other.line).then(self.column.cmp(&other.column))
+    }
+}
+
+#[unstable(feature = "proc_macro_span", issue = "54725")]
+impl PartialOrd for LineColumn {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
 /// The source file of a given `Span`.
 #[unstable(feature = "proc_macro_span", issue = "54725")]
 #[derive(Clone)]
diff --git a/src/libproc_macro/tests/test.rs b/src/libproc_macro/tests/test.rs
new file mode 100644
index 0000000..331b330
--- /dev/null
+++ b/src/libproc_macro/tests/test.rs
@@ -0,0 +1,12 @@
+#![feature(proc_macro_span)]
+
+use proc_macro::LineColumn;
+
+#[test]
+fn test_line_column_ord() {
+    let line0_column0 = LineColumn { line: 0, column: 0 };
+    let line0_column1 = LineColumn { line: 0, column: 1 };
+    let line1_column0 = LineColumn { line: 1, column: 0 };
+    assert!(line0_column0 < line0_column1);
+    assert!(line0_column1 < line1_column0);
+}
diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs
index 916a5ff..075aaa7 100644
--- a/src/librustc_ast/tokenstream.rs
+++ b/src/librustc_ast/tokenstream.rs
@@ -21,6 +21,8 @@
 use rustc_span::{Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
+use log::debug;
+
 use std::{iter, mem};
 
 /// When the main rust parser encounters a syntax-extension invocation, it
@@ -338,8 +340,71 @@
             true
         }
 
-        let mut t1 = self.trees().filter(semantic_tree);
-        let mut t2 = other.trees().filter(semantic_tree);
+        // When comparing two `TokenStream`s, we ignore the `IsJoint` information.
+        //
+        // However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will
+        // use `Token.glue` on adjacent tokens with the proper `IsJoint`.
+        // Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`)
+        // and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent
+        // when determining if two `TokenStream`s are 'probably equal'.
+        //
+        // Therefore, we use `break_two_token_op` to convert all tokens
+        // to the 'unglued' form (if it exists). This ensures that two
+        // `TokenStream`s which differ only in how their tokens are glued
+        // will be considered 'probably equal', which allows us to keep spans.
+        //
+        // This is important when the original `TokenStream` contained
+        // extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces
+        // will be omitted when we pretty-print, which can cause the original
+        // and reparsed `TokenStream`s to differ in the assignment of `IsJoint`,
+        // leading to some tokens being 'glued' together in one stream but not
+        // the other. See #68489 for more details.
+        fn break_tokens(tree: TokenTree) -> impl Iterator<Item = TokenTree> {
+            // In almost all cases, we should have either zero or one levels
+            // of 'unglueing'. However, in some unusual cases, we may need
+            // to iterate breaking tokens mutliple times. For example:
+            // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]'
+            let mut token_trees: SmallVec<[_; 2]>;
+            if let TokenTree::Token(token) = &tree {
+                let mut out = SmallVec::<[_; 2]>::new();
+                out.push(token.clone());
+                // Iterate to fixpoint:
+                // * We start off with 'out' containing our initial token, and `temp` empty
+                // * If we are able to break any tokens in `out`, then `out` will have
+                //   at least one more element than 'temp', so we will try to break tokens
+                //   again.
+                // * If we cannot break any tokens in 'out', we are done
+                loop {
+                    let mut temp = SmallVec::<[_; 2]>::new();
+                    let mut changed = false;
+
+                    for token in out.into_iter() {
+                        if let Some((first, second)) = token.kind.break_two_token_op() {
+                            temp.push(Token::new(first, DUMMY_SP));
+                            temp.push(Token::new(second, DUMMY_SP));
+                            changed = true;
+                        } else {
+                            temp.push(token);
+                        }
+                    }
+                    out = temp;
+                    if !changed {
+                        break;
+                    }
+                }
+                token_trees = out.into_iter().map(|t| TokenTree::Token(t)).collect();
+                if token_trees.len() != 1 {
+                    debug!("break_tokens: broke {:?} to {:?}", tree, token_trees);
+                }
+            } else {
+                token_trees = SmallVec::new();
+                token_trees.push(tree);
+            }
+            token_trees.into_iter()
+        }
+
+        let mut t1 = self.trees().filter(semantic_tree).flat_map(break_tokens);
+        let mut t2 = other.trees().filter(semantic_tree).flat_map(break_tokens);
         for (t1, t2) in t1.by_ref().zip(t2.by_ref()) {
             if !t1.probably_equal_for_proc_macro(&t2) {
                 return false;
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 2cf81af..5d98fde 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -269,7 +269,7 @@
     let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
 
     LoweringContext {
-        crate_root: sess.parse_sess.injected_crate_name.try_get().copied(),
+        crate_root: sess.parse_sess.injected_crate_name.get().copied(),
         sess,
         resolver,
         nt_to_tokenstream,
@@ -688,7 +688,7 @@
     ) -> Span {
         span.fresh_expansion(ExpnData {
             allow_internal_unstable,
-            ..ExpnData::default(ExpnKind::Desugaring(reason), span, self.sess.edition())
+            ..ExpnData::default(ExpnKind::Desugaring(reason), span, self.sess.edition(), None)
         })
     }
 
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 421c6ac..a4e17a5f 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -367,8 +367,8 @@
 
 pub fn provide_extern(providers: &mut Providers<'_>) {
     providers.wasm_import_module_map = |tcx, cnum| {
-        // Build up a map from DefId to a `NativeLibrary` structure, where
-        // `NativeLibrary` internally contains information about
+        // Build up a map from DefId to a `NativeLib` structure, where
+        // `NativeLib` internally contains information about
         // `#[link(wasm_import_module = "...")]` for example.
         let native_libs = tcx.native_libraries(cnum);
 
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index 6ed9cd6..57e018b 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -6,7 +6,6 @@
 use crate::base;
 use crate::common;
 use crate::consts;
-use crate::context::all_outputs_are_pic_executables;
 use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
 use crate::llvm_util;
 use crate::type_::Type;
@@ -150,7 +149,6 @@
     let features = features.join(",");
     let features = CString::new(features).unwrap();
     let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname);
-    let pic_is_pie = all_outputs_are_pic_executables(sess);
     let trap_unreachable = sess.target.target.options.trap_unreachable;
     let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
 
@@ -174,7 +172,6 @@
                 reloc_model,
                 opt_level,
                 use_softfp,
-                pic_is_pie,
                 ffunction_sections,
                 fdata_sections,
                 trap_unreachable,
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index e5f7347..3e17a51 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -100,7 +100,7 @@
     tcx: TyCtxt<'tcx>,
     cgu_name: Symbol,
 ) -> (ModuleCodegen<ModuleLlvm>, u64) {
-    let prof_timer = tcx.prof.generic_activity("codegen_module");
+    let prof_timer = tcx.prof.generic_activity_with_arg("codegen_module", cgu_name.to_string());
     let start_time = Instant::now();
 
     let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 01f90ca..4c810a3 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -97,17 +97,6 @@
     }
 }
 
-/// PIE is potentially more effective than PIC, but can only be used in executables.
-/// If all our outputs are executables, then we can relax PIC to PIE when producing object code.
-/// If the list of crate types is not yet known we conservatively return `false`.
-pub fn all_outputs_are_pic_executables(sess: &Session) -> bool {
-    sess.relocation_model() == RelocModel::Pic
-        && sess
-            .crate_types
-            .try_get()
-            .map_or(false, |crate_types| crate_types.iter().all(|ty| *ty == CrateType::Executable))
-}
-
 fn strip_function_ptr_alignment(data_layout: String) -> String {
     // FIXME: Make this more general.
     data_layout.replace("-Fi8-", "-")
@@ -183,10 +172,11 @@
 
     if sess.relocation_model() == RelocModel::Pic {
         llvm::LLVMRustSetModulePICLevel(llmod);
-    }
-
-    if all_outputs_are_pic_executables(sess) {
-        llvm::LLVMRustSetModulePIELevel(llmod);
+        // PIE is potentially more effective than PIC, but can only be used in executables.
+        // If all our outputs are executables, then we can relax PIC to PIE.
+        if sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
+            llvm::LLVMRustSetModulePIELevel(llmod);
+        }
     }
 
     // If skipping the PLT is enabled, we need to add some module metadata
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index fb9a27e..0cce0b2 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -447,7 +447,6 @@
         unsafe {
             llvm::LLVMRustDIBuilderCreateSubroutineType(
                 DIB(cx),
-                unknown_file_metadata(cx),
                 create_DIArray(DIB(cx), &signature_metadata[..]),
             )
         },
@@ -635,14 +634,12 @@
                     // anything reading the debuginfo for a recursive
                     // type is going to see *something* weird - the only
                     // question is what exactly it will see.
-                    let (size, align) = cx.size_and_align_of(t);
                     let name = "<recur_type>";
                     llvm::LLVMRustDIBuilderCreateBasicType(
                         DIB(cx),
                         name.as_ptr().cast(),
                         name.len(),
-                        size.bits(),
-                        align.bits() as u32,
+                        cx.size_of(t).bits(),
                         DW_ATE_unsigned,
                     )
                 }
@@ -841,14 +838,12 @@
         _ => bug!("debuginfo::basic_type_metadata - `t` is invalid type"),
     };
 
-    let (size, align) = cx.size_and_align_of(t);
     let ty_metadata = unsafe {
         llvm::LLVMRustDIBuilderCreateBasicType(
             DIB(cx),
             name.as_ptr().cast(),
             name.len(),
-            size.bits(),
-            align.bits() as u32,
+            cx.size_of(t).bits(),
             encoding,
         )
     };
@@ -2187,9 +2182,6 @@
                                 name.as_ptr().cast(),
                                 name.len(),
                                 actual_type_metadata,
-                                unknown_file_metadata(cx),
-                                0,
-                                0,
                             ))
                         })
                     } else {
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index 8c9a2c0..8c58084 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -252,7 +252,7 @@
 
         let function_type_metadata = unsafe {
             let fn_signature = get_function_signature(self, fn_abi);
-            llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), file_metadata, fn_signature)
+            llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature)
         };
 
         // Find the enclosing function, in case this is a closure.
@@ -265,8 +265,7 @@
         // name if necessary.
         let generics = self.tcx().generics_of(enclosing_fn_def_id);
         let substs = instance.substs.truncate_to(self.tcx(), generics);
-        let template_parameters =
-            get_template_parameters(self, &generics, substs, file_metadata, &mut name);
+        let template_parameters = get_template_parameters(self, &generics, substs, &mut name);
 
         // Get the linkage_name, which is just the symbol name
         let linkage_name = mangled_name_of_instance(self, instance);
@@ -388,7 +387,6 @@
             cx: &CodegenCx<'ll, 'tcx>,
             generics: &ty::Generics,
             substs: SubstsRef<'tcx>,
-            file_metadata: &'ll DIFile,
             name_to_append_suffix_to: &mut String,
         ) -> &'ll DIArray {
             if substs.types().next().is_none() {
@@ -429,9 +427,6 @@
                                     name.as_ptr().cast(),
                                     name.len(),
                                     actual_type_metadata,
-                                    file_metadata,
-                                    0,
-                                    0,
                                 ))
                             })
                         } else {
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 9cb0f0e..3fb7ff3 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -1655,7 +1655,6 @@
 
     pub fn LLVMRustDIBuilderCreateSubroutineType(
         Builder: &DIBuilder<'a>,
-        File: &'a DIFile,
         ParameterTypes: &'a DIArray,
     ) -> &'a DICompositeType;
 
@@ -1682,7 +1681,6 @@
         Name: *const c_char,
         NameLen: size_t,
         SizeInBits: u64,
-        AlignInBits: u32,
         Encoding: c_uint,
     ) -> &'a DIBasicType;
 
@@ -1880,9 +1878,6 @@
         Name: *const c_char,
         NameLen: size_t,
         Ty: &'a DIType,
-        File: &'a DIFile,
-        LineNo: c_uint,
-        ColumnNo: c_uint,
     ) -> &'a DITemplateTypeParameter;
 
     pub fn LLVMRustDIBuilderCreateNameSpace(
@@ -1948,7 +1943,6 @@
         Reloc: RelocModel,
         Level: CodeGenOptLevel,
         UseSoftFP: bool,
-        PositionIndependentExecutable: bool,
         FunctionSections: bool,
         DataSections: bool,
         TrapUnreachable: bool,
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 286d363..67a2251 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -170,6 +170,7 @@
     ("fp16", Some(sym::aarch64_target_feature)),
     ("rcpc", Some(sym::aarch64_target_feature)),
     ("dotprod", Some(sym::aarch64_target_feature)),
+    ("tme", Some(sym::aarch64_target_feature)),
     ("v8.1a", Some(sym::aarch64_target_feature)),
     ("v8.2a", Some(sym::aarch64_target_feature)),
     ("v8.3a", Some(sym::aarch64_target_feature)),
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index aa4b51f..9a7c490 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -1,12 +1,13 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind};
+use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib};
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
 use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, Sanitizer};
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
+use rustc_session::utils::NativeLibKind;
 /// For all the linkers we support, and information they might
 /// need out of the shared crate context before we get rid of it.
 use rustc_session::{filesearch, Session};
@@ -52,7 +53,7 @@
 ) {
     let _timer = sess.timer("link_binary");
     let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
-    for &crate_type in sess.crate_types.borrow().iter() {
+    for &crate_type in sess.crate_types().iter() {
         // Ignore executable crates if we have -Z no-codegen, as they will error.
         if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen())
             && !output_metadata
@@ -183,6 +184,7 @@
                     "x86_64" => Some("x64".to_string()),
                     "x86" => Some("x86".to_string()),
                     "aarch64" => Some("arm64".to_string()),
+                    "arm" => Some("arm".to_string()),
                     _ => None,
                 };
                 if let Some(ref a) = arch {
@@ -327,11 +329,12 @@
     // metadata of the rlib we're generating somehow.
     for lib in codegen_results.crate_info.used_libraries.iter() {
         match lib.kind {
-            NativeLibraryKind::NativeStatic => {}
-            NativeLibraryKind::NativeStaticNobundle
-            | NativeLibraryKind::NativeFramework
-            | NativeLibraryKind::NativeRawDylib
-            | NativeLibraryKind::NativeUnknown => continue,
+            NativeLibKind::StaticBundle => {}
+            NativeLibKind::StaticNoBundle
+            | NativeLibKind::Dylib
+            | NativeLibKind::Framework
+            | NativeLibKind::RawDylib
+            | NativeLibKind::Unspecified => continue,
         }
         if let Some(name) = lib.name {
             ab.add_native_library(name);
@@ -430,7 +433,7 @@
         // object files come from where and selectively skip them.
         let skip_object_files = native_libs
             .iter()
-            .any(|lib| lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib));
+            .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
         ab.add_rlib(
             path,
             &name.as_str(),
@@ -872,11 +875,8 @@
 
     // If we're only producing artifacts that are archives, no need to preserve
     // the objects as they're losslessly contained inside the archives.
-    let output_linked = sess
-        .crate_types
-        .borrow()
-        .iter()
-        .any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib);
+    let output_linked =
+        sess.crate_types().iter().any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib);
     if !output_linked {
         return false;
     }
@@ -907,26 +907,28 @@
     StaticlibBase,
 }
 
-fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
+fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
     let lib_args: Vec<_> = all_native_libs
         .iter()
         .filter(|l| relevant_lib(sess, l))
         .filter_map(|lib| {
             let name = lib.name?;
             match lib.kind {
-                NativeLibraryKind::NativeStaticNobundle | NativeLibraryKind::NativeUnknown => {
+                NativeLibKind::StaticNoBundle
+                | NativeLibKind::Dylib
+                | NativeLibKind::Unspecified => {
                     if sess.target.target.options.is_like_msvc {
                         Some(format!("{}.lib", name))
                     } else {
                         Some(format!("-l{}", name))
                     }
                 }
-                NativeLibraryKind::NativeFramework => {
+                NativeLibKind::Framework => {
                     // ld-only syntax, since there are no frameworks in MSVC
                     Some(format!("-framework {}", name))
                 }
                 // These are included, no need to print them
-                NativeLibraryKind::NativeStatic | NativeLibraryKind::NativeRawDylib => None,
+                NativeLibKind::StaticBundle | NativeLibKind::RawDylib => None,
             }
         })
         .collect();
@@ -1696,11 +1698,11 @@
             None => continue,
         };
         match lib.kind {
-            NativeLibraryKind::NativeUnknown => cmd.link_dylib(name),
-            NativeLibraryKind::NativeFramework => cmd.link_framework(name),
-            NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(name),
-            NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(name, &search_path),
-            NativeLibraryKind::NativeRawDylib => {
+            NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
+            NativeLibKind::Framework => cmd.link_framework(name),
+            NativeLibKind::StaticNoBundle => cmd.link_staticlib(name),
+            NativeLibKind::StaticBundle => cmd.link_whole_staticlib(name, &search_path),
+            NativeLibKind::RawDylib => {
                 // FIXME(#58713): Proper handling for raw dylibs.
                 bug!("raw_dylib feature not yet implemented");
             }
@@ -1890,7 +1892,7 @@
         let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
         let skip_native = native_libs
             .iter()
-            .any(|lib| lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib));
+            .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
 
         if (!are_upstream_rust_objects_already_included(sess)
             || ignored_for_lto(sess, &codegen_results.crate_info, cnum))
@@ -2032,9 +2034,9 @@
                 continue;
             }
             match lib.kind {
-                NativeLibraryKind::NativeUnknown => cmd.link_dylib(name),
-                NativeLibraryKind::NativeFramework => cmd.link_framework(name),
-                NativeLibraryKind::NativeStaticNobundle => {
+                NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
+                NativeLibKind::Framework => cmd.link_framework(name),
+                NativeLibKind::StaticNoBundle => {
                     // Link "static-nobundle" native libs only if the crate they originate from
                     // is being linked statically to the current crate.  If it's linked dynamically
                     // or is an rlib already included via some other dylib crate, the symbols from
@@ -2046,8 +2048,8 @@
                 // ignore statically included native libraries here as we've
                 // already included them when we included the rust library
                 // previously
-                NativeLibraryKind::NativeStatic => {}
-                NativeLibraryKind::NativeRawDylib => {
+                NativeLibKind::StaticBundle => {}
+                NativeLibKind::RawDylib => {
                     // FIXME(#58713): Proper handling for raw dylibs.
                     bug!("raw_dylib feature not yet implemented");
                 }
@@ -2056,7 +2058,7 @@
     }
 }
 
-fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
+fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
     match lib.cfg {
         Some(ref cfg) => rustc_attr::cfg_matches(cfg, &sess.parse_sess, None),
         None => true,
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index ee5bcf4..49de8c5 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -44,8 +44,7 @@
         LinkerInfo {
             exports: tcx
                 .sess
-                .crate_types
-                .borrow()
+                .crate_types()
                 .iter()
                 .map(|&c| (c, exported_symbols(tcx, c)))
                 .collect(),
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index c0272e1..970d13b 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -18,7 +18,7 @@
 use rustc_session::config::{CrateType, Sanitizer};
 
 pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
-    crates_export_threshold(&tcx.sess.crate_types.borrow())
+    crates_export_threshold(&tcx.sess.crate_types())
 }
 
 fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
@@ -212,7 +212,7 @@
         }));
     }
 
-    if tcx.sess.crate_types.borrow().contains(&CrateType::Dylib) {
+    if tcx.sess.crate_types().contains(&CrateType::Dylib) {
         let symbol_name = metadata_symbol_name(tcx);
         let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
 
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index 53dfe7c..9e03c28 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -142,8 +142,22 @@
         let emit_obj = if !should_emit_obj {
             EmitObj::None
         } else if sess.target.target.options.obj_is_bitcode
-            || sess.opts.cg.linker_plugin_lto.enabled()
+            || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins)
         {
+            // This case is selected if the target uses objects as bitcode, or
+            // if linker plugin LTO is enabled. In the linker plugin LTO case
+            // the assumption is that the final link-step will read the bitcode
+            // and convert it to object code. This may be done by either the
+            // native linker or rustc itself.
+            //
+            // Note, however, that the linker-plugin-lto requested here is
+            // explicitly ignored for `#![no_builtins]` crates. These crates are
+            // specifically ignored by rustc's LTO passes and wouldn't work if
+            // loaded into the linker. These crates define symbols that LLVM
+            // lowers intrinsics to, and these symbol dependencies aren't known
+            // until after codegen. As a result any crate marked
+            // `#![no_builtins]` is assumed to not participate in LTO and
+            // instead goes on to generate object code.
             EmitObj::Bitcode
         } else if need_bitcode_in_object(sess) {
             EmitObj::ObjectCode(BitcodeSection::Full)
@@ -368,7 +382,7 @@
 
 fn need_bitcode_in_object(sess: &Session) -> bool {
     let requested_for_rlib = sess.opts.cg.embed_bitcode
-        && sess.crate_types.borrow().contains(&CrateType::Rlib)
+        && sess.crate_types().contains(&CrateType::Rlib)
         && sess.opts.output_types.contains_key(&OutputType::Exe);
     let forced_by_target = sess.target.target.options.forces_embed_bitcode;
     requested_for_rlib || forced_by_target
@@ -977,7 +991,7 @@
     };
     let cgcx = CodegenContext::<B> {
         backend: backend.clone(),
-        crate_types: sess.crate_types.borrow().clone(),
+        crate_types: sess.crate_types().to_vec(),
         each_linked_rlib_for_lto,
         lto: sess.lto(),
         no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort,
@@ -1798,7 +1812,7 @@
     );
 
     tcx.sess.target.target.options.is_like_msvc &&
-        tcx.sess.crate_types.borrow().iter().any(|ct| *ct == CrateType::Rlib) &&
+        tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
     // ThinLTO can't handle this workaround in all cases, so we don't
     // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
     // dynamic linking when linker plugin LTO is enabled.
diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs
index 29398db..5b14258 100644
--- a/src/librustc_codegen_ssa/base.rs
+++ b/src/librustc_codegen_ssa/base.rs
@@ -44,6 +44,7 @@
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{self, EntryFnType};
+use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
 use rustc_span::Span;
 use rustc_symbol_mangling::test as symbol_names_test;
@@ -895,7 +896,7 @@
             .native_libraries(krate)
             .iter()
             .filter(|lib| {
-                if lib.kind != cstore::NativeLibraryKind::NativeUnknown {
+                if !matches!(lib.kind, NativeLibKind::Dylib | NativeLibKind::Unspecified) {
                     return false;
                 }
                 let cfg = match lib.cfg {
@@ -947,7 +948,7 @@
         match compute_per_cgu_lto_type(
             &tcx.sess.lto(),
             &tcx.sess.opts,
-            &tcx.sess.crate_types.borrow(),
+            &tcx.sess.crate_types(),
             ModuleKind::Regular,
         ) {
             ComputedLtoType::No => CguReuse::PostLto,
diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs
index 7dc09b5..bd37218 100644
--- a/src/librustc_codegen_ssa/lib.rs
+++ b/src/librustc_codegen_ssa/lib.rs
@@ -24,7 +24,7 @@
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::LangItem;
 use rustc_middle::dep_graph::WorkProduct;
-use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLibrary};
+use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLib};
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::ty::query::Providers;
 use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT};
@@ -112,9 +112,9 @@
     pub compiler_builtins: Option<CrateNum>,
     pub profiler_runtime: Option<CrateNum>,
     pub is_no_builtins: FxHashSet<CrateNum>,
-    pub native_libraries: FxHashMap<CrateNum, Lrc<Vec<NativeLibrary>>>,
+    pub native_libraries: FxHashMap<CrateNum, Lrc<Vec<NativeLib>>>,
     pub crate_name: FxHashMap<CrateNum, String>,
-    pub used_libraries: Lrc<Vec<NativeLibrary>>,
+    pub used_libraries: Lrc<Vec<NativeLib>>,
     pub link_args: Lrc<Vec<String>>,
     pub used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>,
     pub used_crates_static: Vec<(CrateNum, LibSource)>,
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index 81ad032..6772122 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -15,6 +15,7 @@
 log = "0.4"
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
 lazy_static = "1"
+once_cell = { version = "1", features = ["parking_lot"] }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 graphviz = { path = "../libgraphviz" }
 cfg-if = "0.1.2"
diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs
index 2a0139f..9383be4 100644
--- a/src/librustc_data_structures/flock.rs
+++ b/src/librustc_data_structures/flock.rs
@@ -7,18 +7,22 @@
 #![allow(non_camel_case_types)]
 #![allow(nonstandard_style)]
 
+use std::fs::{File, OpenOptions};
 use std::io;
 use std::path::Path;
 
 cfg_if! {
-    if #[cfg(unix)] {
-        use std::ffi::{CString, OsStr};
-        use std::mem;
+    // We use `flock` rather than `fcntl` on Linux, because WSL1 does not support
+    // `fcntl`-style advisory locks properly (rust-lang/rust#72157).
+    //
+    // For other Unix targets we still use `fcntl` because it's more portable than
+    // `flock`.
+    if #[cfg(target_os = "linux")] {
         use std::os::unix::prelude::*;
 
         #[derive(Debug)]
         pub struct Lock {
-            fd: libc::c_int,
+            _file: File,
         }
 
         impl Lock {
@@ -27,23 +31,56 @@
                        create: bool,
                        exclusive: bool)
                        -> io::Result<Lock> {
-                let os: &OsStr = p.as_ref();
-                let buf = CString::new(os.as_bytes()).unwrap();
-                let open_flags = if create {
-                    libc::O_RDWR | libc::O_CREAT
+                let file = OpenOptions::new()
+                    .read(true)
+                    .write(true)
+                    .create(create)
+                    .mode(libc::S_IRWXU as u32)
+                    .open(p)?;
+
+                let mut operation = if exclusive {
+                    libc::LOCK_EX
                 } else {
-                    libc::O_RDWR
+                    libc::LOCK_SH
                 };
-
-                let fd = unsafe {
-                    libc::open(buf.as_ptr(), open_flags,
-                               libc::S_IRWXU as libc::c_int)
-                };
-
-                if fd < 0 {
-                    return Err(io::Error::last_os_error());
+                if !wait {
+                    operation |= libc::LOCK_NB
                 }
 
+                let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
+                if ret == -1 {
+                    Err(io::Error::last_os_error())
+                } else {
+                    Ok(Lock { _file: file })
+                }
+            }
+        }
+
+        // Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by
+        // `flock` is associated with the file descriptor and closing the file release it
+        // automatically.
+    } else if #[cfg(unix)] {
+        use std::mem;
+        use std::os::unix::prelude::*;
+
+        #[derive(Debug)]
+        pub struct Lock {
+            file: File,
+        }
+
+        impl Lock {
+            pub fn new(p: &Path,
+                       wait: bool,
+                       create: bool,
+                       exclusive: bool)
+                       -> io::Result<Lock> {
+                let file = OpenOptions::new()
+                    .read(true)
+                    .write(true)
+                    .create(create)
+                    .mode(libc::S_IRWXU as u32)
+                    .open(p)?;
+
                 let lock_type = if exclusive {
                     libc::F_WRLCK
                 } else {
@@ -58,14 +95,12 @@
 
                 let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK };
                 let ret = unsafe {
-                    libc::fcntl(fd, cmd, &flock)
+                    libc::fcntl(file.as_raw_fd(), cmd, &flock)
                 };
                 if ret == -1 {
-                    let err = io::Error::last_os_error();
-                    unsafe { libc::close(fd); }
-                    Err(err)
+                    Err(io::Error::last_os_error())
                 } else {
-                    Ok(Lock { fd })
+                    Ok(Lock { file })
                 }
             }
         }
@@ -79,15 +114,13 @@
                 flock.l_len = 0;
 
                 unsafe {
-                    libc::fcntl(self.fd, libc::F_SETLK, &flock);
-                    libc::close(self.fd);
+                    libc::fcntl(self.file.as_raw_fd(), libc::F_SETLK, &flock);
                 }
             }
         }
     } else if #[cfg(windows)] {
         use std::mem;
         use std::os::windows::prelude::*;
-        use std::fs::{File, OpenOptions};
 
         use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK};
         use winapi::um::fileapi::LockFileEx;
diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs
index 9051b17..39afb3d 100644
--- a/src/librustc_data_structures/sync.rs
+++ b/src/librustc_data_structures/sync.rs
@@ -20,7 +20,6 @@
 use crate::owning_ref::{Erased, OwningRef};
 use std::collections::HashMap;
 use std::hash::{BuildHasher, Hash};
-use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
 
 pub use std::sync::atomic::Ordering;
@@ -230,6 +229,8 @@
         pub use std::cell::RefMut as LockGuard;
         pub use std::cell::RefMut as MappedLockGuard;
 
+        pub use once_cell::unsync::OnceCell;
+
         use std::cell::RefCell as InnerRwLock;
         use std::cell::RefCell as InnerLock;
 
@@ -313,6 +314,8 @@
         pub use parking_lot::MutexGuard as LockGuard;
         pub use parking_lot::MappedMutexGuard as MappedLockGuard;
 
+        pub use once_cell::sync::OnceCell;
+
         pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
 
         pub use crossbeam_utils::atomic::AtomicCell;
@@ -432,134 +435,6 @@
     }
 }
 
-/// A type whose inner value can be written once and then will stay read-only
-// This contains a PhantomData<T> since this type conceptually owns a T outside the Mutex once
-// initialized. This ensures that Once<T> is Sync only if T is. If we did not have PhantomData<T>
-// we could send a &Once<Cell<bool>> to multiple threads and call `get` on it to get access
-// to &Cell<bool> on those threads.
-pub struct Once<T>(Lock<Option<T>>, PhantomData<T>);
-
-impl<T> Once<T> {
-    /// Creates an Once value which is uninitialized
-    #[inline(always)]
-    pub fn new() -> Self {
-        Once(Lock::new(None), PhantomData)
-    }
-
-    /// Consumes the value and returns Some(T) if it was initialized
-    #[inline(always)]
-    pub fn into_inner(self) -> Option<T> {
-        self.0.into_inner()
-    }
-
-    /// Tries to initialize the inner value to `value`.
-    /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it
-    /// otherwise if the inner value was already set it returns `value` back to the caller
-    #[inline]
-    pub fn try_set(&self, value: T) -> Option<T> {
-        let mut lock = self.0.lock();
-        if lock.is_some() {
-            return Some(value);
-        }
-        *lock = Some(value);
-        None
-    }
-
-    /// Tries to initialize the inner value to `value`.
-    /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it
-    /// otherwise if the inner value was already set it asserts that `value` is equal to the inner
-    /// value and then returns `value` back to the caller
-    #[inline]
-    pub fn try_set_same(&self, value: T) -> Option<T>
-    where
-        T: Eq,
-    {
-        let mut lock = self.0.lock();
-        if let Some(ref inner) = *lock {
-            assert!(*inner == value);
-            return Some(value);
-        }
-        *lock = Some(value);
-        None
-    }
-
-    /// Tries to initialize the inner value to `value` and panics if it was already initialized
-    #[inline]
-    pub fn set(&self, value: T) {
-        assert!(self.try_set(value).is_none());
-    }
-
-    /// Initializes the inner value if it wasn't already done by calling the provided closure. It
-    /// ensures that no-one else can access the value in the mean time by holding a lock for the
-    /// duration of the closure.
-    /// A reference to the inner value is returned.
-    #[inline]
-    pub fn init_locking<F: FnOnce() -> T>(&self, f: F) -> &T {
-        {
-            let mut lock = self.0.lock();
-            if lock.is_none() {
-                *lock = Some(f());
-            }
-        }
-
-        self.borrow()
-    }
-
-    /// Tries to initialize the inner value by calling the closure without ensuring that no-one
-    /// else can access it. This mean when this is called from multiple threads, multiple
-    /// closures may concurrently be computing a value which the inner value should take.
-    /// Only one of these closures are used to actually initialize the value.
-    /// If some other closure already set the value,
-    /// we return the value our closure computed wrapped in a `Option`.
-    /// If our closure set the value, `None` is returned.
-    /// If the value is already initialized, the closure is not called and `None` is returned.
-    #[inline]
-    pub fn init_nonlocking<F: FnOnce() -> T>(&self, f: F) -> Option<T> {
-        if self.0.lock().is_some() { None } else { self.try_set(f()) }
-    }
-
-    /// Tries to initialize the inner value by calling the closure without ensuring that no-one
-    /// else can access it. This mean when this is called from multiple threads, multiple
-    /// closures may concurrently be computing a value which the inner value should take.
-    /// Only one of these closures are used to actually initialize the value.
-    /// If some other closure already set the value, we assert that it our closure computed
-    /// a value equal to the value already set and then
-    /// we return the value our closure computed wrapped in a `Option`.
-    /// If our closure set the value, `None` is returned.
-    /// If the value is already initialized, the closure is not called and `None` is returned.
-    #[inline]
-    pub fn init_nonlocking_same<F: FnOnce() -> T>(&self, f: F) -> Option<T>
-    where
-        T: Eq,
-    {
-        if self.0.lock().is_some() { None } else { self.try_set_same(f()) }
-    }
-
-    /// Tries to get a reference to the inner value, returns `None` if it is not yet initialized
-    #[inline(always)]
-    pub fn try_get(&self) -> Option<&T> {
-        let lock = &*self.0.lock();
-        if let Some(ref inner) = *lock {
-            // This is safe since we won't mutate the inner value
-            unsafe { Some(&*(inner as *const T)) }
-        } else {
-            None
-        }
-    }
-
-    /// Gets reference to the inner value, panics if it is not yet initialized
-    #[inline(always)]
-    pub fn get(&self) -> &T {
-        self.try_get().expect("value was not set")
-    }
-
-    /// Gets reference to the inner value, panics if it is not yet initialized
-    #[inline(always)]
-    pub fn borrow(&self) -> &T {
-        self.get()
-    }
-}
-
 #[derive(Debug)]
 pub struct Lock<T>(InnerLock<T>);
 
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 6847b17..68ce93d 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -586,7 +586,7 @@
         if let Input::File(file) = compiler.input() {
             // FIXME: #![crate_type] and #![crate_name] support not implemented yet
             let attrs = vec![];
-            sess.crate_types.set(collect_crate_types(sess, &attrs));
+            sess.init_crate_types(collect_crate_types(sess, &attrs));
             let outputs = compiler.build_output_filenames(&sess, &attrs);
             let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| {
                 sess.fatal(&format!("failed to read rlink file: {}", err));
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index a443b8f..0a21eb8 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -396,7 +396,7 @@
                 annotation.pp_ann(),
                 false,
                 parse.edition,
-                parse.injected_crate_name.try_get().is_some(),
+                parse.injected_crate_name.get().is_some(),
             )
         })
     } else {
@@ -438,7 +438,7 @@
                     annotation.pp_ann(),
                     true,
                     parse.edition,
-                    parse.injected_crate_name.try_get().is_some(),
+                    parse.injected_crate_name.get().is_some(),
                 )
             })
         }
diff --git a/src/librustc_error_codes/error_codes/E0590.md b/src/librustc_error_codes/error_codes/E0590.md
index df7aa4f..11005b8 100644
--- a/src/librustc_error_codes/error_codes/E0590.md
+++ b/src/librustc_error_codes/error_codes/E0590.md
@@ -1,13 +1,17 @@
-`break` or `continue` must include a label when used in the condition of a
-`while` loop.
+`break` or `continue` keywords were used in a condition of a `while` loop
+without a label.
 
-Example of erroneous code:
+Erroneous code code:
 
 ```compile_fail,E0590
 while break {}
 ```
 
+`break` or `continue` must include a label when used in the condition of a
+`while` loop.
+
 To fix this, add a label specifying which loop is being broken out of:
+
 ```
 'foo: while break 'foo {}
 ```
diff --git a/src/librustc_error_codes/error_codes/E0593.md b/src/librustc_error_codes/error_codes/E0593.md
index b32923a..1902d73 100644
--- a/src/librustc_error_codes/error_codes/E0593.md
+++ b/src/librustc_error_codes/error_codes/E0593.md
@@ -11,3 +11,14 @@
     foo(|y| { });
 }
 ```
+
+You have to provide the same number of arguments as expected by the `Fn`-based
+type. So to fix the previous example, we need to remove the `y` argument:
+
+```
+fn foo<F: Fn()>(x: F) { }
+
+fn main() {
+    foo(|| { }); // ok!
+}
+```
diff --git a/src/librustc_error_codes/error_codes/E0599.md b/src/librustc_error_codes/error_codes/E0599.md
index c44e605..5b1590b 100644
--- a/src/librustc_error_codes/error_codes/E0599.md
+++ b/src/librustc_error_codes/error_codes/E0599.md
@@ -9,3 +9,18 @@
 x.chocolate(); // error: no method named `chocolate` found for type `Mouth`
                //        in the current scope
 ```
+
+In this case, you need to implement the `chocolate` method to fix the error:
+
+```
+struct Mouth;
+
+impl Mouth {
+    fn chocolate(&self) { // We implement the `chocolate` method here.
+        println!("Hmmm! I love chocolate!");
+    }
+}
+
+let x = Mouth;
+x.chocolate(); // ok!
+```
diff --git a/src/librustc_error_codes/error_codes/E0600.md b/src/librustc_error_codes/error_codes/E0600.md
index 172e2a3..356006c 100644
--- a/src/librustc_error_codes/error_codes/E0600.md
+++ b/src/librustc_error_codes/error_codes/E0600.md
@@ -1,6 +1,6 @@
 An unary operator was used on a type which doesn't implement it.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0600
 enum Question {
diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs
index fe5bf6f..0137080 100644
--- a/src/librustc_expand/base.rs
+++ b/src/librustc_expand/base.rs
@@ -13,6 +13,7 @@
 use rustc_errors::{DiagnosticBuilder, ErrorReported};
 use rustc_parse::{self, parser, MACRO_ARGUMENTS};
 use rustc_session::parse::ParseSess;
+use rustc_span::def_id::DefId;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind};
 use rustc_span::source_map::SourceMap;
@@ -857,7 +858,13 @@
         SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition)
     }
 
-    pub fn expn_data(&self, parent: ExpnId, call_site: Span, descr: Symbol) -> ExpnData {
+    pub fn expn_data(
+        &self,
+        parent: ExpnId,
+        call_site: Span,
+        descr: Symbol,
+        macro_def_id: Option<DefId>,
+    ) -> ExpnData {
         ExpnData {
             kind: ExpnKind::Macro(self.macro_kind(), descr),
             parent,
@@ -867,6 +874,7 @@
             allow_internal_unsafe: self.allow_internal_unsafe,
             local_inner_macros: self.local_inner_macros,
             edition: self.edition,
+            macro_def_id,
         }
     }
 }
diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs
index 485c514..b505302 100644
--- a/src/librustc_expand/expand.rs
+++ b/src/librustc_expand/expand.rs
@@ -988,6 +988,7 @@
                     ExpnKind::Macro(MacroKind::Attr, sym::derive),
                     item.span(),
                     self.cx.parse_sess.edition,
+                    None,
                 )
             }),
             _ => None,
diff --git a/src/librustc_infer/infer/canonical/canonicalizer.rs b/src/librustc_infer/infer/canonical/canonicalizer.rs
index 5551b56..c2dae6b 100644
--- a/src/librustc_infer/infer/canonical/canonicalizer.rs
+++ b/src/librustc_infer/infer/canonical/canonicalizer.rs
@@ -332,7 +332,6 @@
             ty::ReStatic
             | ty::ReEarlyBound(..)
             | ty::ReFree(_)
-            | ty::ReScope(_)
             | ty::ReEmpty(_)
             | ty::RePlaceholder(..)
             | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs
index c7a7cf8..23c9eeb 100644
--- a/src/librustc_infer/infer/canonical/query_response.rs
+++ b/src/librustc_infer/infer/canonical/query_response.rs
@@ -25,7 +25,7 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, BoundVar, Const, Ty, TyCtxt};
+use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt};
 use std::fmt::Debug;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
@@ -532,12 +532,14 @@
                 cause.clone(),
                 param_env,
                 match k1.unpack() {
-                    GenericArgKind::Lifetime(r1) => ty::Predicate::RegionOutlives(
+                    GenericArgKind::Lifetime(r1) => ty::PredicateKind::RegionOutlives(
                         ty::Binder::bind(ty::OutlivesPredicate(r1, r2)),
-                    ),
-                    GenericArgKind::Type(t1) => {
-                        ty::Predicate::TypeOutlives(ty::Binder::bind(ty::OutlivesPredicate(t1, r2)))
-                    }
+                    )
+                    .to_predicate(self.tcx),
+                    GenericArgKind::Type(t1) => ty::PredicateKind::TypeOutlives(ty::Binder::bind(
+                        ty::OutlivesPredicate(t1, r2),
+                    ))
+                    .to_predicate(self.tcx),
                     GenericArgKind::Const(..) => {
                         // Consts cannot outlive one another, so we don't expect to
                         // ecounter this branch.
@@ -664,9 +666,10 @@
         self.obligations.push(Obligation {
             cause: self.cause.clone(),
             param_env: self.param_env,
-            predicate: ty::Predicate::RegionOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
+            predicate: ty::PredicateKind::RegionOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
                 sup, sub,
-            ))),
+            )))
+            .to_predicate(self.infcx.tcx),
             recursion_depth: 0,
         });
     }
diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs
index 3467457..70a2122 100644
--- a/src/librustc_infer/infer/combine.rs
+++ b/src/librustc_infer/infer/combine.rs
@@ -39,7 +39,7 @@
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{IntType, UintType};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -307,7 +307,7 @@
             self.obligations.push(Obligation::new(
                 self.trace.cause.clone(),
                 self.param_env,
-                ty::Predicate::WellFormed(b_ty),
+                ty::PredicateKind::WellFormed(b_ty).to_predicate(self.infcx.tcx),
             ));
         }
 
@@ -398,11 +398,15 @@
         b: &'tcx ty::Const<'tcx>,
     ) {
         let predicate = if a_is_expected {
-            ty::Predicate::ConstEquate(a, b)
+            ty::PredicateKind::ConstEquate(a, b)
         } else {
-            ty::Predicate::ConstEquate(b, a)
+            ty::PredicateKind::ConstEquate(b, a)
         };
-        self.obligations.push(Obligation::new(self.trace.cause.clone(), self.param_env, predicate));
+        self.obligations.push(Obligation::new(
+            self.trace.cause.clone(),
+            self.param_env,
+            predicate.to_predicate(self.tcx()),
+        ));
     }
 }
 
@@ -615,7 +619,6 @@
             | ty::ReVar(..)
             | ty::ReEmpty(_)
             | ty::ReStatic
-            | ty::ReScope(..)
             | ty::ReEarlyBound(..)
             | ty::ReFree(..) => {
                 // see common code below
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index a8d6c01..cc479aa 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -61,7 +61,6 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Node;
-use rustc_middle::middle::region;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
     self,
@@ -81,58 +80,12 @@
 
 pub(super) fn note_and_explain_region(
     tcx: TyCtxt<'tcx>,
-    region_scope_tree: &region::ScopeTree,
     err: &mut DiagnosticBuilder<'_>,
     prefix: &str,
     region: ty::Region<'tcx>,
     suffix: &str,
 ) {
     let (description, span) = match *region {
-        ty::ReScope(scope) => {
-            let new_string;
-            let unknown_scope =
-                || format!("{}unknown scope: {:?}{}.  Please report a bug.", prefix, scope, suffix);
-            let span = scope.span(tcx, region_scope_tree);
-            let hir_id = scope.hir_id(region_scope_tree);
-            let tag = match hir_id.and_then(|hir_id| tcx.hir().find(hir_id)) {
-                Some(Node::Block(_)) => "block",
-                Some(Node::Expr(expr)) => match expr.kind {
-                    hir::ExprKind::Call(..) => "call",
-                    hir::ExprKind::MethodCall(..) => "method call",
-                    hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
-                    hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let",
-                    hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for",
-                    hir::ExprKind::Match(..) => "match",
-                    _ => "expression",
-                },
-                Some(Node::Stmt(_)) => "statement",
-                Some(Node::Item(it)) => item_scope_tag(&it),
-                Some(Node::TraitItem(it)) => trait_item_scope_tag(&it),
-                Some(Node::ImplItem(it)) => impl_item_scope_tag(&it),
-                Some(_) | None => {
-                    err.span_note(span, &unknown_scope());
-                    return;
-                }
-            };
-            let scope_decorated_tag = match scope.data {
-                region::ScopeData::Node => tag,
-                region::ScopeData::CallSite => "scope of call-site for function",
-                region::ScopeData::Arguments => "scope of function body",
-                region::ScopeData::Destruction => {
-                    new_string = format!("destruction scope surrounding {}", tag);
-                    &new_string[..]
-                }
-                region::ScopeData::Remainder(first_statement_index) => {
-                    new_string = format!(
-                        "block suffix following statement {}",
-                        first_statement_index.index()
-                    );
-                    &new_string[..]
-                }
-            };
-            explain_span(tcx, scope_decorated_tag, span)
-        }
-
         ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
             msg_span_from_free_region(tcx, region)
         }
@@ -284,7 +237,6 @@
 
 pub fn unexpected_hidden_region_diagnostic(
     tcx: TyCtxt<'tcx>,
-    region_scope_tree: Option<&region::ScopeTree>,
     span: Span,
     hidden_ty: Ty<'tcx>,
     hidden_region: ty::Region<'tcx>,
@@ -297,64 +249,56 @@
     );
 
     // Explain the region we are capturing.
-    if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) = hidden_region {
-        // Assuming regionck succeeded (*), we ought to always be
-        // capturing *some* region from the fn header, and hence it
-        // ought to be free. So under normal circumstances, we will go
-        // down this path which gives a decent human readable
-        // explanation.
-        //
-        // (*) if not, the `tainted_by_errors` field would be set to
-        // `Some(ErrorReported)` in any case, so we wouldn't be here at all.
-        note_and_explain_free_region(
-            tcx,
-            &mut err,
-            &format!("hidden type `{}` captures ", hidden_ty),
-            hidden_region,
-            "",
-        );
-    } else {
-        // Ugh. This is a painful case: the hidden region is not one
-        // that we can easily summarize or explain. This can happen
-        // in a case like
-        // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`:
-        //
-        // ```
-        // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> {
-        //   if condition() { a } else { b }
-        // }
-        // ```
-        //
-        // Here the captured lifetime is the intersection of `'a` and
-        // `'b`, which we can't quite express.
-
-        if let Some(region_scope_tree) = region_scope_tree {
-            // If the `region_scope_tree` is available, this is being
-            // invoked from the "region inferencer error". We can at
-            // least report a really cryptic error for now.
-            note_and_explain_region(
+    match hidden_region {
+        ty::ReEmpty(ty::UniverseIndex::ROOT) => {
+            // All lifetimes shorter than the function body are `empty` in
+            // lexical region resolution. The default explanation of "an empty
+            // lifetime" isn't really accurate here.
+            let message = format!(
+                "hidden type `{}` captures lifetime smaller than the function body",
+                hidden_ty
+            );
+            err.span_note(span, &message);
+        }
+        ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) => {
+            // Assuming regionck succeeded (*), we ought to always be
+            // capturing *some* region from the fn header, and hence it
+            // ought to be free. So under normal circumstances, we will go
+            // down this path which gives a decent human readable
+            // explanation.
+            //
+            // (*) if not, the `tainted_by_errors` field would be set to
+            // `Some(ErrorReported)` in any case, so we wouldn't be here at all.
+            note_and_explain_free_region(
                 tcx,
-                region_scope_tree,
                 &mut err,
                 &format!("hidden type `{}` captures ", hidden_ty),
                 hidden_region,
                 "",
             );
-        } else {
-            // If the `region_scope_tree` is *unavailable*, this is
-            // being invoked by the code that comes *after* region
-            // inferencing. This is a bug, as the region inferencer
-            // ought to have noticed the failed constraint and invoked
-            // error reporting, which in turn should have prevented us
-            // from getting trying to infer the hidden type
-            // completely.
-            tcx.sess.delay_span_bug(
-                span,
-                &format!(
-                    "hidden type captures unexpected lifetime `{:?}` \
-                     but no region inference failure",
-                    hidden_region,
-                ),
+        }
+        _ => {
+            // Ugh. This is a painful case: the hidden region is not one
+            // that we can easily summarize or explain. This can happen
+            // in a case like
+            // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`:
+            //
+            // ```
+            // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> {
+            //   if condition() { a } else { b }
+            // }
+            // ```
+            //
+            // Here the captured lifetime is the intersection of `'a` and
+            // `'b`, which we can't quite express.
+
+            // We can at least report a really cryptic error for now.
+            note_and_explain_region(
+                tcx,
+                &mut err,
+                &format!("hidden type `{}` captures ", hidden_ty),
+                hidden_region,
+                "",
             );
         }
     }
@@ -363,11 +307,7 @@
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    pub fn report_region_errors(
-        &self,
-        region_scope_tree: &region::ScopeTree,
-        errors: &Vec<RegionResolutionError<'tcx>>,
-    ) {
+    pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
         debug!("report_region_errors(): {} errors to start", errors.len());
 
         // try to pre-process the errors, which will group some of them
@@ -390,17 +330,14 @@
                     // general bit of code that displays the error information
                     RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
                         if sub.is_placeholder() || sup.is_placeholder() {
-                            self.report_placeholder_failure(region_scope_tree, origin, sub, sup)
-                                .emit();
+                            self.report_placeholder_failure(origin, sub, sup).emit();
                         } else {
-                            self.report_concrete_failure(region_scope_tree, origin, sub, sup)
-                                .emit();
+                            self.report_concrete_failure(origin, sub, sup).emit();
                         }
                     }
 
                     RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => {
                         self.report_generic_bound_failure(
-                            region_scope_tree,
                             origin.span(),
                             Some(origin),
                             param_ty,
@@ -417,29 +354,12 @@
                         sup_r,
                     ) => {
                         if sub_r.is_placeholder() {
-                            self.report_placeholder_failure(
-                                region_scope_tree,
-                                sub_origin,
-                                sub_r,
-                                sup_r,
-                            )
-                            .emit();
+                            self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit();
                         } else if sup_r.is_placeholder() {
-                            self.report_placeholder_failure(
-                                region_scope_tree,
-                                sup_origin,
-                                sub_r,
-                                sup_r,
-                            )
-                            .emit();
+                            self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
                         } else {
                             self.report_sub_sup_conflict(
-                                region_scope_tree,
-                                var_origin,
-                                sub_origin,
-                                sub_r,
-                                sup_origin,
-                                sup_r,
+                                var_origin, sub_origin, sub_r, sup_origin, sup_r,
                             );
                         }
                     }
@@ -460,13 +380,7 @@
                         // value.
                         let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe));
 
-                        self.report_placeholder_failure(
-                            region_scope_tree,
-                            sup_origin,
-                            sub_r,
-                            sup_r,
-                        )
-                        .emit();
+                        self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
                     }
 
                     RegionResolutionError::MemberConstraintFailure {
@@ -477,7 +391,6 @@
                         let hidden_ty = self.resolve_vars_if_possible(&hidden_ty);
                         unexpected_hidden_region_diagnostic(
                             self.tcx,
-                            Some(region_scope_tree),
                             span,
                             hidden_ty,
                             member_region,
@@ -1754,19 +1667,16 @@
 
     pub fn report_generic_bound_failure(
         &self,
-        region_scope_tree: &region::ScopeTree,
         span: Span,
         origin: Option<SubregionOrigin<'tcx>>,
         bound_kind: GenericKind<'tcx>,
         sub: Region<'tcx>,
     ) {
-        self.construct_generic_bound_failure(region_scope_tree, span, origin, bound_kind, sub)
-            .emit();
+        self.construct_generic_bound_failure(span, origin, bound_kind, sub).emit();
     }
 
     pub fn construct_generic_bound_failure(
         &self,
-        region_scope_tree: &region::ScopeTree,
         span: Span,
         origin: Option<SubregionOrigin<'tcx>>,
         bound_kind: GenericKind<'tcx>,
@@ -1918,7 +1828,6 @@
                 ));
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
                     &mut err,
                     &format!("{} must be valid for ", labeled_user_string),
                     sub,
@@ -1936,7 +1845,6 @@
 
     fn report_sub_sup_conflict(
         &self,
-        region_scope_tree: &region::ScopeTree,
         var_origin: RegionVariableOrigin,
         sub_origin: SubregionOrigin<'tcx>,
         sub_region: Region<'tcx>,
@@ -1947,7 +1855,6 @@
 
         note_and_explain_region(
             self.tcx,
-            region_scope_tree,
             &mut err,
             "first, the lifetime cannot outlive ",
             sup_region,
@@ -1973,7 +1880,6 @@
                 if sub_expected == sup_expected && sub_found == sup_found {
                     note_and_explain_region(
                         self.tcx,
-                        region_scope_tree,
                         &mut err,
                         "...but the lifetime must also be valid for ",
                         sub_region,
@@ -1995,7 +1901,6 @@
 
         note_and_explain_region(
             self.tcx,
-            region_scope_tree,
             &mut err,
             "but, the lifetime must be valid for ",
             sub_region,
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs
index 2aed3d9..efe5268 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs
@@ -8,7 +8,6 @@
 mod different_lifetimes;
 mod find_anon_type;
 mod named_anon_conflict;
-mod outlives_closure;
 mod placeholder_error;
 mod static_impl_trait;
 mod trait_impl_difference;
@@ -57,7 +56,6 @@
                 ErrorReported
             })
             .or_else(|| self.try_report_anon_anon_conflict())
-            .or_else(|| self.try_report_outlives_closure())
             .or_else(|| self.try_report_static_impl_trait())
             .or_else(|| self.try_report_impl_not_conforming_to_trait())
     }
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs
deleted file mode 100644
index fc858a4..0000000
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-//! Error Reporting for Anonymous Region Lifetime Errors
-//! where both the regions are anonymous.
-
-use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::infer::lexical_region_resolve::RegionResolutionError::SubSupConflict;
-use crate::infer::SubregionOrigin;
-use rustc_errors::ErrorReported;
-use rustc_hir::{Expr, ExprKind::Closure, Node};
-use rustc_middle::ty::RegionKind;
-
-impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
-    /// Print the error message for lifetime errors when binding escapes a closure.
-    ///
-    /// Consider a case where we have
-    ///
-    /// ```no_run
-    /// fn with_int<F>(f: F) where F: FnOnce(&isize) {
-    ///     let x = 3;
-    ///     f(&x);
-    /// }
-    /// fn main() {
-    ///     let mut x = None;
-    ///     with_int(|y| x = Some(y));
-    /// }
-    /// ```
-    ///
-    /// the output will be
-    ///
-    /// ```text
-    ///     let mut x = None;
-    ///         ----- borrowed data cannot be stored into here...
-    ///     with_int(|y| x = Some(y));
-    ///              ---          ^ cannot be stored outside of its closure
-    ///              |
-    ///              ...because it cannot outlive this closure
-    /// ```
-    pub(super) fn try_report_outlives_closure(&self) -> Option<ErrorReported> {
-        if let Some(SubSupConflict(_, origin, ref sub_origin, _, ref sup_origin, sup_region)) =
-            self.error
-        {
-            // #45983: when trying to assign the contents of an argument to a binding outside of a
-            // closure, provide a specific message pointing this out.
-            if let (
-                &SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span),
-                &RegionKind::ReFree(ref free_region),
-            ) = (&sub_origin, sup_region)
-            {
-                let hir = &self.tcx().hir();
-                if let Some(def_id) = free_region.scope.as_local() {
-                    let hir_id = hir.as_local_hir_id(def_id);
-                    if let Node::Expr(Expr { kind: Closure(_, _, _, closure_span, None), .. }) =
-                        hir.get(hir_id)
-                    {
-                        let sup_sp = sup_origin.span();
-                        let origin_sp = origin.span();
-                        let mut err = self.tcx().sess.struct_span_err(
-                            sup_sp,
-                            "borrowed data cannot be stored outside of its closure",
-                        );
-                        err.span_label(sup_sp, "cannot be stored outside of its closure");
-                        if origin_sp == sup_sp || origin_sp.contains(sup_sp) {
-                            // // sup_sp == origin.span():
-                            //
-                            // let mut x = None;
-                            //     ----- borrowed data cannot be stored into here...
-                            // with_int(|y| x = Some(y));
-                            //          ---          ^ cannot be stored outside of its closure
-                            //          |
-                            //          ...because it cannot outlive this closure
-                            //
-                            // // origin.contains(&sup_sp):
-                            //
-                            // let mut f: Option<&u32> = None;
-                            //     ----- borrowed data cannot be stored into here...
-                            // closure_expecting_bound(|x: &'x u32| {
-                            //                         ------------ ... because it cannot outlive this closure
-                            //     f = Some(x);
-                            //              ^ cannot be stored outside of its closure
-                            err.span_label(
-                                *external_span,
-                                "borrowed data cannot be stored into here...",
-                            );
-                            err.span_label(
-                                *closure_span,
-                                "...because it cannot outlive this closure",
-                            );
-                        } else {
-                            // FIXME: the wording for this case could be much improved
-                            //
-                            // let mut lines_to_use: Vec<&CrateId> = Vec::new();
-                            //                           - cannot infer an appropriate lifetime...
-                            // let push_id = |installed_id: &CrateId| {
-                            //     -------   ------------------------ borrowed data cannot outlive this closure
-                            //     |
-                            //     ...so that variable is valid at time of its declaration
-                            //     lines_to_use.push(installed_id);
-                            //                       ^^^^^^^^^^^^ cannot be stored outside of its closure
-                            err.span_label(origin_sp, "cannot infer an appropriate lifetime...");
-                            err.span_label(
-                                *external_span,
-                                "...so that variable is valid at time of its \
-                                            declaration",
-                            );
-                            err.span_label(
-                                *closure_span,
-                                "borrowed data cannot outlive this closure",
-                            );
-                        }
-                        err.emit();
-                        return Some(ErrorReported);
-                    }
-                }
-            }
-        }
-        None
-    }
-}
diff --git a/src/librustc_infer/infer/error_reporting/note.rs b/src/librustc_infer/infer/error_reporting/note.rs
index 81f3783..8fbb89d 100644
--- a/src/librustc_infer/infer/error_reporting/note.rs
+++ b/src/librustc_infer/infer/error_reporting/note.rs
@@ -1,7 +1,6 @@
 use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt};
 use crate::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
-use rustc_middle::middle::region;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{self, Region};
 
@@ -38,65 +37,12 @@
                 let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
                 err.span_note(span, &format!("...so that closure can access `{}`", var_name));
             }
-            infer::InfStackClosure(span) => {
-                err.span_note(span, "...so that closure does not outlive its stack frame");
-            }
-            infer::InvokeClosure(span) => {
-                err.span_note(span, "...so that closure is not invoked outside its lifetime");
-            }
-            infer::DerefPointer(span) => {
-                err.span_note(span, "...so that pointer is not dereferenced outside its lifetime");
-            }
-            infer::ClosureCapture(span, id) => {
-                err.span_note(
-                    span,
-                    &format!(
-                        "...so that captured variable `{}` does not outlive the \
-                                        enclosing closure",
-                        self.tcx.hir().name(id)
-                    ),
-                );
-            }
-            infer::IndexSlice(span) => {
-                err.span_note(span, "...so that slice is not indexed outside the lifetime");
-            }
             infer::RelateObjectBound(span) => {
                 err.span_note(span, "...so that it can be closed over into an object");
             }
-            infer::CallRcvr(span) => {
-                err.span_note(span, "...so that method receiver is valid for the method call");
-            }
-            infer::CallArg(span) => {
-                err.span_note(span, "...so that argument is valid for the call");
-            }
             infer::CallReturn(span) => {
                 err.span_note(span, "...so that return value is valid for the call");
             }
-            infer::Operand(span) => {
-                err.span_note(span, "...so that operand is valid for operation");
-            }
-            infer::AddrOf(span) => {
-                err.span_note(span, "...so that reference is valid at the time of borrow");
-            }
-            infer::AutoBorrow(span) => {
-                err.span_note(span, "...so that auto-reference is valid at the time of borrow");
-            }
-            infer::ExprTypeIsNotInScope(t, span) => {
-                err.span_note(
-                    span,
-                    &format!(
-                        "...so type `{}` of expression is valid during the \
-                                        expression",
-                        self.ty_to_string(t)
-                    ),
-                );
-            }
-            infer::BindingTypeIsNotValidAtDecl(span) => {
-                err.span_note(span, "...so that variable is valid at time of its declaration");
-            }
-            infer::ParameterInScope(_, span) => {
-                err.span_note(span, "...so that a type/lifetime parameter is in scope here");
-            }
             infer::DataBorrowed(ty, span) => {
                 err.span_note(
                     span,
@@ -126,25 +72,12 @@
                     ),
                 );
             }
-            infer::RelateDefaultParamBound(span, t) => {
-                err.span_note(
-                    span,
-                    &format!(
-                        "...so that type parameter instantiated with `{}`, will \
-                                        meet its declared lifetime bounds",
-                        self.ty_to_string(t)
-                    ),
-                );
-            }
             infer::RelateRegionParamBound(span) => {
                 err.span_note(
                     span,
                     "...so that the declared lifetime parameter bounds are satisfied",
                 );
             }
-            infer::SafeDestructor(span) => {
-                err.span_note(span, "...so that references are valid when the destructor runs");
-            }
             infer::CompareImplMethodObligation { span, .. } => {
                 err.span_note(
                     span,
@@ -157,7 +90,6 @@
 
     pub(super) fn report_concrete_failure(
         &self,
-        region_scope_tree: &region::ScopeTree,
         origin: SubregionOrigin<'tcx>,
         sub: Region<'tcx>,
         sup: Region<'tcx>,
@@ -166,10 +98,9 @@
             infer::Subtype(box trace) => {
                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
                 let mut err = self.report_and_explain_type_error(trace, &terr);
-                note_and_explain_region(self.tcx, region_scope_tree, &mut err, "", sup, "...");
+                note_and_explain_region(self.tcx, &mut err, "", sup, "...");
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
                     &mut err,
                     "...does not necessarily outlive ",
                     sub,
@@ -187,7 +118,6 @@
                 );
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
                     &mut err,
                     "...the reference is valid for ",
                     sub,
@@ -195,7 +125,6 @@
                 );
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
                     &mut err,
                     "...but the borrowed content is only valid for ",
                     sup,
@@ -215,7 +144,6 @@
                 );
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
                     &mut err,
                     "...the borrowed pointer is valid for ",
                     sub,
@@ -223,7 +151,6 @@
                 );
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
                     &mut err,
                     &format!("...but `{}` is only valid for ", var_name),
                     sup,
@@ -231,106 +158,6 @@
                 );
                 err
             }
-            infer::InfStackClosure(span) => {
-                let mut err =
-                    struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame");
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "...the closure must be valid for ",
-                    sub,
-                    "...",
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "...but the closure's stack frame is only valid \
-                                                  for ",
-                    sup,
-                    "",
-                );
-                err
-            }
-            infer::InvokeClosure(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0315,
-                    "cannot invoke closure outside of its lifetime"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the closure is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
-            infer::DerefPointer(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0473,
-                    "dereference of reference outside its lifetime"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the reference is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
-            infer::ClosureCapture(span, id) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0474,
-                    "captured variable `{}` does not outlive the \
-                                                enclosing closure",
-                    self.tcx.hir().name(id)
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "captured variable is valid for ",
-                    sup,
-                    "",
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "closure is valid for ",
-                    sub,
-                    "",
-                );
-                err
-            }
-            infer::IndexSlice(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0475,
-                    "index of slice outside its lifetime"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the slice is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
             infer::RelateObjectBound(span) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
@@ -339,17 +166,9 @@
                     "lifetime of the source pointer does not outlive \
                                                 lifetime bound of the object type"
                 );
+                note_and_explain_region(self.tcx, &mut err, "object type is valid for ", sub, "");
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "object type is valid for ",
-                    sub,
-                    "",
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
                     &mut err,
                     "source pointer is only valid for ",
                     sup,
@@ -367,22 +186,10 @@
                     self.ty_to_string(ty)
                 );
                 match *sub {
-                    ty::ReStatic => note_and_explain_region(
-                        self.tcx,
-                        region_scope_tree,
-                        &mut err,
-                        "type must satisfy ",
-                        sub,
-                        "",
-                    ),
-                    _ => note_and_explain_region(
-                        self.tcx,
-                        region_scope_tree,
-                        &mut err,
-                        "type must outlive ",
-                        sub,
-                        "",
-                    ),
+                    ty::ReStatic => {
+                        note_and_explain_region(self.tcx, &mut err, "type must satisfy ", sub, "")
+                    }
+                    _ => note_and_explain_region(self.tcx, &mut err, "type must outlive ", sub, ""),
                 }
                 err
             }
@@ -391,7 +198,6 @@
                     struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
                     &mut err,
                     "lifetime parameter instantiated with ",
                     sup,
@@ -399,7 +205,6 @@
                 );
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
                     &mut err,
                     "but lifetime parameter must outlive ",
                     sub,
@@ -407,61 +212,6 @@
                 );
                 err
             }
-            infer::RelateDefaultParamBound(span, ty) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0479,
-                    "the type `{}` (provided as the value of a type \
-                                                parameter) is not valid at this point",
-                    self.ty_to_string(ty)
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "type must outlive ",
-                    sub,
-                    "",
-                );
-                err
-            }
-            infer::CallRcvr(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0480,
-                    "lifetime of method receiver does not outlive the \
-                                                method call"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the receiver is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
-            infer::CallArg(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0481,
-                    "lifetime of function argument does not outlive \
-                                                the function call"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the function argument is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
             infer::CallReturn(span) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
@@ -472,7 +222,6 @@
                 );
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
                     &mut err,
                     "the return value is only valid for ",
                     sup,
@@ -480,140 +229,6 @@
                 );
                 err
             }
-            infer::Operand(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0483,
-                    "lifetime of operand does not outlive the \
-                                                operation"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the operand is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
-            infer::AddrOf(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0484,
-                    "reference is not valid at the time of borrow"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the borrow is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
-            infer::AutoBorrow(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0485,
-                    "automatically reference is not valid at the time \
-                                                of borrow"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the automatic borrow is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
-            infer::ExprTypeIsNotInScope(t, span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0486,
-                    "type of expression contains references that are \
-                                                not valid during the expression: `{}`",
-                    self.ty_to_string(t)
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "type is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
-            infer::SafeDestructor(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0487,
-                    "unsafe use of destructor: destructor might be \
-                                                called while references are dead"
-                );
-                // FIXME (22171): terms "super/subregion" are suboptimal
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "superregion: ",
-                    sup,
-                    "",
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "subregion: ",
-                    sub,
-                    "",
-                );
-                err
-            }
-            infer::BindingTypeIsNotValidAtDecl(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0488,
-                    "lifetime of variable does not enclose its \
-                                                declaration"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the variable is only valid for ",
-                    sup,
-                    "",
-                );
-                err
-            }
-            infer::ParameterInScope(_, span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0489,
-                    "type/lifetime parameter not in scope here"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the parameter is only valid for ",
-                    sub,
-                    "",
-                );
-                err
-            }
             infer::DataBorrowed(ty, span) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
@@ -622,22 +237,8 @@
                     "a value of type `{}` is borrowed for too long",
                     self.ty_to_string(ty)
                 );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the type is valid for ",
-                    sub,
-                    "",
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "but the borrow lasts for ",
-                    sup,
-                    "",
-                );
+                note_and_explain_region(self.tcx, &mut err, "the type is valid for ", sub, "");
+                note_and_explain_region(self.tcx, &mut err, "but the borrow lasts for ", sup, "");
                 err
             }
             infer::ReferenceOutlivesReferent(ty, span) => {
@@ -648,17 +249,9 @@
                     "in type `{}`, reference has a longer lifetime than the data it references",
                     self.ty_to_string(ty)
                 );
+                note_and_explain_region(self.tcx, &mut err, "the pointer is valid for ", sub, "");
                 note_and_explain_region(
                     self.tcx,
-                    region_scope_tree,
-                    &mut err,
-                    "the pointer is valid for ",
-                    sub,
-                    "",
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    region_scope_tree,
                     &mut err,
                     "but the referenced data is only valid for ",
                     sup,
@@ -683,7 +276,6 @@
 
     pub(super) fn report_placeholder_failure(
         &self,
-        region_scope_tree: &region::ScopeTree,
         placeholder_origin: SubregionOrigin<'tcx>,
         sub: Region<'tcx>,
         sup: Region<'tcx>,
@@ -695,7 +287,7 @@
                 self.report_and_explain_type_error(trace, &terr)
             }
 
-            _ => self.report_concrete_failure(region_scope_tree, placeholder_origin, sub, sup),
+            _ => self.report_concrete_failure(placeholder_origin, sub, sup),
         }
     }
 }
diff --git a/src/librustc_infer/infer/free_regions.rs b/src/librustc_infer/infer/free_regions.rs
index e31c524..d975038 100644
--- a/src/librustc_infer/infer/free_regions.rs
+++ b/src/librustc_infer/infer/free_regions.rs
@@ -5,7 +5,6 @@
 
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 use rustc_hir::def_id::DefId;
-use rustc_middle::middle::region;
 use rustc_middle::ty::{self, Lift, Region, TyCtxt};
 
 /// Combines a `region::ScopeTree` (which governs relationships between
@@ -21,21 +20,13 @@
     /// The context used to fetch the region maps.
     pub context: DefId,
 
-    /// The region maps for the given context.
-    pub region_scope_tree: &'a region::ScopeTree,
-
     /// Free-region relationships.
     pub free_regions: &'a FreeRegionMap<'tcx>,
 }
 
 impl<'a, 'tcx> RegionRelations<'a, 'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        context: DefId,
-        region_scope_tree: &'a region::ScopeTree,
-        free_regions: &'a FreeRegionMap<'tcx>,
-    ) -> Self {
-        Self { tcx, context, region_scope_tree, free_regions }
+    pub fn new(tcx: TyCtxt<'tcx>, context: DefId, free_regions: &'a FreeRegionMap<'tcx>) -> Self {
+        Self { tcx, context, free_regions }
     }
 
     pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> {
diff --git a/src/librustc_infer/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs
index c9ed687..b4cfcb3 100644
--- a/src/librustc_infer/infer/freshen.rs
+++ b/src/librustc_infer/infer/freshen.rs
@@ -127,7 +127,6 @@
             ty::ReStatic
             | ty::ReEarlyBound(..)
             | ty::ReFree(_)
-            | ty::ReScope(_)
             | ty::ReVar(_)
             | ty::RePlaceholder(..)
             | ty::ReEmpty(_)
diff --git a/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs b/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs
deleted file mode 100644
index 5d3e8f4..0000000
--- a/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs
+++ /dev/null
@@ -1,253 +0,0 @@
-//! This module provides linkage between libgraphviz traits and
-//! `rustc_trait_selection::infer::region_constraints`, generating a
-//! rendering of the graph represented by the list of `Constraint`
-//! instances (which make up the edges of the graph), as well as the
-//! origin for each constraint (which are attached to the labels on
-//! each edge).
-
-/// For clarity, rename the graphviz crate locally to dot.
-use graphviz as dot;
-
-use super::Constraint;
-use crate::infer::region_constraints::RegionConstraintData;
-use crate::infer::RegionRelations;
-use crate::infer::SubregionOrigin;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::DefIndex;
-use rustc_middle::middle::region;
-use rustc_middle::ty;
-
-use std::borrow::Cow;
-use std::collections::btree_map::BTreeMap;
-use std::collections::hash_map::Entry::Vacant;
-use std::env;
-use std::fs;
-use std::io;
-use std::sync::atomic::{AtomicBool, Ordering};
-
-fn print_help_message() {
-    println!(
-        "\
--Z print-region-graph by default prints a region constraint graph for every \n\
-function body, to the path `constraints.nodeXXX.dot`, where the XXX is \n\
-replaced with the node id of the function under analysis.                   \n\
-                                                                            \n\
-To select one particular function body, set `RUST_REGION_GRAPH_NODE=XXX`,   \n\
-where XXX is the node id desired.                                           \n\
-                                                                            \n\
-To generate output to some path other than the default                      \n\
-`constraints.nodeXXX.dot`, set `RUST_REGION_GRAPH=/path/desired.dot`;  \n\
-occurrences of the character `%` in the requested path will be replaced with\n\
-the node id of the function under analysis.                                 \n\
-                                                                            \n\
-(Since you requested help via RUST_REGION_GRAPH=help, no region constraint  \n\
-graphs will be printed.                                                     \n\
-"
-    );
-}
-
-pub fn maybe_print_constraints_for<'a, 'tcx>(
-    region_data: &RegionConstraintData<'tcx>,
-    region_rels: &RegionRelations<'a, 'tcx>,
-) {
-    let tcx = region_rels.tcx;
-    let context = region_rels.context;
-
-    if !tcx.sess.opts.debugging_opts.print_region_graph {
-        return;
-    }
-
-    let requested_node = env::var("RUST_REGION_GRAPH_NODE")
-        .ok()
-        .and_then(|s| s.parse().map(DefIndex::from_u32).ok());
-
-    if requested_node.is_some() && requested_node != Some(context.index) {
-        return;
-    }
-
-    let requested_output = env::var("RUST_REGION_GRAPH");
-    debug!("requested_output: {:?} requested_node: {:?}", requested_output, requested_node);
-
-    let output_path = {
-        let output_template = match requested_output {
-            Ok(ref s) if s == "help" => {
-                static PRINTED_YET: AtomicBool = AtomicBool::new(false);
-                if !PRINTED_YET.load(Ordering::SeqCst) {
-                    print_help_message();
-                    PRINTED_YET.store(true, Ordering::SeqCst);
-                }
-                return;
-            }
-
-            Ok(other_path) => other_path,
-            Err(_) => "constraints.node%.dot".to_string(),
-        };
-
-        if output_template.is_empty() {
-            panic!("empty string provided as RUST_REGION_GRAPH");
-        }
-
-        if output_template.contains('%') {
-            let mut new_str = String::new();
-            for c in output_template.chars() {
-                if c == '%' {
-                    new_str.push_str(&context.index.as_u32().to_string());
-                } else {
-                    new_str.push(c);
-                }
-            }
-            new_str
-        } else {
-            output_template
-        }
-    };
-
-    if let Err(e) = dump_region_data_to(region_rels, &region_data.constraints, &output_path) {
-        let msg = format!("io error dumping region constraints: {}", e);
-        tcx.sess.err(&msg)
-    }
-}
-
-struct ConstraintGraph<'a, 'tcx> {
-    graph_name: String,
-    region_rels: &'a RegionRelations<'a, 'tcx>,
-    map: &'a BTreeMap<Constraint<'tcx>, SubregionOrigin<'tcx>>,
-    node_ids: FxHashMap<Node, usize>,
-}
-
-#[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)]
-enum Node {
-    RegionVid(ty::RegionVid),
-    Region(ty::RegionKind),
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Copy)]
-enum Edge<'tcx> {
-    Constraint(Constraint<'tcx>),
-    EnclScope(region::Scope, region::Scope),
-}
-
-impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> {
-    fn new(
-        name: String,
-        region_rels: &'a RegionRelations<'a, 'tcx>,
-        map: &'a ConstraintMap<'tcx>,
-    ) -> ConstraintGraph<'a, 'tcx> {
-        let mut i = 0;
-        let mut node_ids = FxHashMap::default();
-        {
-            let mut add_node = |node| {
-                if let Vacant(e) = node_ids.entry(node) {
-                    e.insert(i);
-                    i += 1;
-                }
-            };
-
-            for (n1, n2) in map.keys().map(|c| constraint_to_nodes(c)) {
-                add_node(n1);
-                add_node(n2);
-            }
-
-            region_rels.region_scope_tree.each_encl_scope(|sub, sup| {
-                add_node(Node::Region(ty::ReScope(sub)));
-                add_node(Node::Region(ty::ReScope(sup)));
-            });
-        }
-
-        ConstraintGraph { map, node_ids, region_rels, graph_name: name }
-    }
-}
-
-impl<'a, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'tcx> {
-    type Node = Node;
-    type Edge = Edge<'tcx>;
-    fn graph_id(&self) -> dot::Id<'_> {
-        dot::Id::new(&*self.graph_name).unwrap()
-    }
-    fn node_id(&self, n: &Node) -> dot::Id<'_> {
-        let node_id = match self.node_ids.get(n) {
-            Some(node_id) => node_id,
-            None => bug!("no node_id found for node: {:?}", n),
-        };
-        let name = || format!("node_{}", node_id);
-
-        dot::Id::new(name())
-            .unwrap_or_else(|_| bug!("failed to create graphviz node identified by {}", name()))
-    }
-    fn node_label(&self, n: &Node) -> dot::LabelText<'_> {
-        match *n {
-            Node::RegionVid(n_vid) => dot::LabelText::label(format!("{:?}", n_vid)),
-            Node::Region(n_rgn) => dot::LabelText::label(format!("{:?}", n_rgn)),
-        }
-    }
-    fn edge_label(&self, e: &Edge<'_>) -> dot::LabelText<'_> {
-        match *e {
-            Edge::Constraint(ref c) => {
-                dot::LabelText::label(format!("{:?}", self.map.get(c).unwrap()))
-            }
-            Edge::EnclScope(..) => dot::LabelText::label("(enclosed)".to_owned()),
-        }
-    }
-}
-
-fn constraint_to_nodes(c: &Constraint<'_>) -> (Node, Node) {
-    match *c {
-        Constraint::VarSubVar(rv_1, rv_2) => (Node::RegionVid(rv_1), Node::RegionVid(rv_2)),
-        Constraint::RegSubVar(r_1, rv_2) => (Node::Region(*r_1), Node::RegionVid(rv_2)),
-        Constraint::VarSubReg(rv_1, r_2) => (Node::RegionVid(rv_1), Node::Region(*r_2)),
-        Constraint::RegSubReg(r_1, r_2) => (Node::Region(*r_1), Node::Region(*r_2)),
-    }
-}
-
-fn edge_to_nodes(e: &Edge<'_>) -> (Node, Node) {
-    match *e {
-        Edge::Constraint(ref c) => constraint_to_nodes(c),
-        Edge::EnclScope(sub, sup) => {
-            (Node::Region(ty::ReScope(sub)), Node::Region(ty::ReScope(sup)))
-        }
-    }
-}
-
-impl<'a, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'tcx> {
-    type Node = Node;
-    type Edge = Edge<'tcx>;
-    fn nodes(&self) -> dot::Nodes<'_, Node> {
-        let set = self.node_ids.keys().cloned().collect::<FxHashSet<_>>();
-        debug!("constraint graph has {} nodes", set.len());
-        set.into_iter().collect()
-    }
-    fn edges(&self) -> dot::Edges<'_, Edge<'tcx>> {
-        debug!("constraint graph has {} edges", self.map.len());
-        let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect();
-        self.region_rels
-            .region_scope_tree
-            .each_encl_scope(|sub, sup| v.push(Edge::EnclScope(sub, sup)));
-        debug!("region graph has {} edges", v.len());
-        Cow::Owned(v)
-    }
-    fn source(&self, edge: &Edge<'tcx>) -> Node {
-        let (n1, _) = edge_to_nodes(edge);
-        debug!("edge {:?} has source {:?}", edge, n1);
-        n1
-    }
-    fn target(&self, edge: &Edge<'tcx>) -> Node {
-        let (_, n2) = edge_to_nodes(edge);
-        debug!("edge {:?} has target {:?}", edge, n2);
-        n2
-    }
-}
-
-pub type ConstraintMap<'tcx> = BTreeMap<Constraint<'tcx>, SubregionOrigin<'tcx>>;
-
-fn dump_region_data_to<'a, 'tcx>(
-    region_rels: &RegionRelations<'a, 'tcx>,
-    map: &ConstraintMap<'tcx>,
-    path: &str,
-) -> io::Result<()> {
-    debug!("dump_region_data map (len: {}) path: {}", map.len(), path);
-    let g = ConstraintGraph::new("region_data".to_string(), region_rels, map);
-    debug!("dump_region_data calling render");
-    let mut v = Vec::new();
-    dot::render(&g, &mut v).unwrap();
-    fs::write(path, &v)
-}
diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs
index 33a80fb..fcf1949 100644
--- a/src/librustc_infer/infer/lexical_region_resolve/mod.rs
+++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs
@@ -18,13 +18,11 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
-use rustc_middle::ty::{ReLateBound, RePlaceholder, ReScope, ReVar};
+use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
 use rustc_middle::ty::{Region, RegionVid};
 use rustc_span::Span;
 use std::fmt;
 
-mod graphviz;
-
 /// This function performs lexical region resolution given a complete
 /// set of constraints and variable origins. It performs a fixed-point
 /// iteration to find region values which satisfy all constraints,
@@ -49,7 +47,10 @@
             let mut values = resolver.infer_variable_values(&mut errors);
             let re_erased = region_rels.tcx.lifetimes.re_erased;
 
-            values.values.iter_mut().for_each(|v| *v = VarValue::Value(re_erased));
+            values.values.iter_mut().for_each(|v| match *v {
+                VarValue::Value(ref mut r) => *r = re_erased,
+                VarValue::ErrorValue => {}
+            });
             (values, errors)
         }
         RegionckMode::Erase { suppress_errors: true } => {
@@ -146,7 +147,6 @@
             self.region_rels.context,
             self.dump_constraints(self.region_rels)
         );
-        graphviz::maybe_print_constraints_for(&self.data, self.region_rels);
 
         let graph = self.construct_graph();
         self.expand_givens(&graph);
@@ -290,8 +290,8 @@
 
         // Find all the "upper bounds" -- that is, each region `b` such that
         // `r0 <= b` must hold.
-        let (member_upper_bounds, _) =
-            self.collect_concrete_regions(graph, member_vid, OUTGOING, None);
+        let (member_upper_bounds, ..) =
+            self.collect_bounding_regions(graph, member_vid, OUTGOING, None);
 
         // Get an iterator over the *available choice* -- that is,
         // each choice region `c` where `lb <= c` and `c <= ub` for all the
@@ -423,15 +423,6 @@
 
         match *b_data {
             VarValue::Value(cur_region) => {
-                // Identical scopes can show up quite often, if the fixed point
-                // iteration converges slowly. Skip them. This is purely an
-                // optimization.
-                if let (ReScope(a_scope), ReScope(cur_scope)) = (a_region, cur_region) {
-                    if a_scope == cur_scope {
-                        return false;
-                    }
-                }
-
                 // This is a specialized version of the `lub_concrete_regions`
                 // check below for a common case, here purely as an
                 // optimization.
@@ -525,8 +516,8 @@
                 self.tcx().lifetimes.re_static
             }
 
-            (&ReEmpty(_), r @ (ReEarlyBound(_) | ReFree(_) | ReScope(_)))
-            | (r @ (ReEarlyBound(_) | ReFree(_) | ReScope(_)), &ReEmpty(_)) => {
+            (&ReEmpty(_), r @ (ReEarlyBound(_) | ReFree(_)))
+            | (r @ (ReEarlyBound(_) | ReFree(_)), &ReEmpty(_)) => {
                 // All empty regions are less than early-bound, free,
                 // and scope regions.
                 r
@@ -551,46 +542,6 @@
                 }
             }
 
-            (&ReEarlyBound(_) | &ReFree(_), &ReScope(s_id))
-            | (&ReScope(s_id), &ReEarlyBound(_) | &ReFree(_)) => {
-                // A "free" region can be interpreted as "some region
-                // at least as big as fr.scope".  So, we can
-                // reasonably compare free regions and scopes:
-                let fr_scope = match (a, b) {
-                    (&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => {
-                        self.region_rels.region_scope_tree.early_free_scope(self.tcx(), br)
-                    }
-                    (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => {
-                        self.region_rels.region_scope_tree.free_scope(self.tcx(), fr)
-                    }
-                    _ => bug!(),
-                };
-                let r_id =
-                    self.region_rels.region_scope_tree.nearest_common_ancestor(fr_scope, s_id);
-                if r_id == fr_scope {
-                    // if the free region's scope `fr.scope` is bigger than
-                    // the scope region `s_id`, then the LUB is the free
-                    // region itself:
-                    match (a, b) {
-                        (_, &ReScope(_)) => return a,
-                        (&ReScope(_), _) => return b,
-                        _ => bug!(),
-                    }
-                }
-
-                // otherwise, we don't know what the free region is,
-                // so we must conservatively say the LUB is static:
-                self.tcx().lifetimes.re_static
-            }
-
-            (&ReScope(a_id), &ReScope(b_id)) => {
-                // The region corresponding to an outer block is a
-                // subtype of the region corresponding to an inner
-                // block.
-                let lub = self.region_rels.region_scope_tree.nearest_common_ancestor(a_id, b_id);
-                self.tcx().mk_region(ReScope(lub))
-            }
-
             (&ReEarlyBound(_) | &ReFree(_), &ReEarlyBound(_) | &ReFree(_)) => {
                 self.region_rels.lub_free_regions(a, b)
             }
@@ -659,7 +610,7 @@
                     if !self.sub_concrete_regions(a_region, b_region) {
                         debug!(
                             "collect_errors: region error at {:?}: \
-                             cannot verify that {:?}={:?} <= {:?}",
+                            cannot verify that {:?}={:?} <= {:?}",
                             origin, a_vid, a_region, b_region
                         );
                         *a_data = VarValue::ErrorValue;
@@ -716,7 +667,7 @@
         graph: &RegionGraph<'tcx>,
         errors: &mut Vec<RegionResolutionError<'tcx>>,
     ) {
-        debug!("collect_var_errors");
+        debug!("collect_var_errors, var_data = {:#?}", var_data.values);
 
         // This is the best way that I have found to suppress
         // duplicate and related errors. Basically we keep a set of
@@ -815,10 +766,10 @@
     ) {
         // Errors in expanding nodes result from a lower-bound that is
         // not contained by an upper-bound.
-        let (mut lower_bounds, lower_dup) =
-            self.collect_concrete_regions(graph, node_idx, INCOMING, Some(dup_vec));
-        let (mut upper_bounds, upper_dup) =
-            self.collect_concrete_regions(graph, node_idx, OUTGOING, Some(dup_vec));
+        let (mut lower_bounds, lower_vid_bounds, lower_dup) =
+            self.collect_bounding_regions(graph, node_idx, INCOMING, Some(dup_vec));
+        let (mut upper_bounds, _, upper_dup) =
+            self.collect_bounding_regions(graph, node_idx, OUTGOING, Some(dup_vec));
 
         if lower_dup || upper_dup {
             return;
@@ -874,15 +825,22 @@
         // If we have a scenario like `exists<'a> { forall<'b> { 'b:
         // 'a } }`, we wind up without any lower-bound -- all we have
         // are placeholders as upper bounds, but the universe of the
-        // variable `'a` doesn't permit those placeholders.
+        // variable `'a`, or some variable that `'a` has to outlive, doesn't
+        // permit those placeholders.
+        let min_universe = lower_vid_bounds
+            .into_iter()
+            .map(|vid| self.var_infos[vid].universe)
+            .min()
+            .expect("lower_vid_bounds should at least include `node_idx`");
+
         for upper_bound in &upper_bounds {
             if let ty::RePlaceholder(p) = upper_bound.region {
-                if node_universe.cannot_name(p.universe) {
+                if min_universe.cannot_name(p.universe) {
                     let origin = self.var_infos[node_idx].origin;
                     errors.push(RegionResolutionError::UpperBoundUniverseConflict(
                         node_idx,
                         origin,
-                        node_universe,
+                        min_universe,
                         upper_bound.origin.clone(),
                         upper_bound.region,
                     ));
@@ -904,13 +862,24 @@
         );
     }
 
-    fn collect_concrete_regions(
+    /// Collects all regions that "bound" the variable `orig_node_idx` in the
+    /// given direction.
+    ///
+    /// If `dup_vec` is `Some` it's used to track duplicates between successive
+    /// calls of this function.
+    ///
+    /// The return tuple fields are:
+    /// - a list of all concrete regions bounding the given region.
+    /// - the set of all region variables bounding the given region.
+    /// - a `bool` that's true if the returned region variables overlap with
+    ///   those returned by a previous call for another region.
+    fn collect_bounding_regions(
         &self,
         graph: &RegionGraph<'tcx>,
         orig_node_idx: RegionVid,
         dir: Direction,
         mut dup_vec: Option<&mut IndexVec<RegionVid, Option<RegionVid>>>,
-    ) -> (Vec<RegionAndOrigin<'tcx>>, bool) {
+    ) -> (Vec<RegionAndOrigin<'tcx>>, FxHashSet<RegionVid>, bool) {
         struct WalkState<'tcx> {
             set: FxHashSet<RegionVid>,
             stack: Vec<RegionVid>,
@@ -929,9 +898,7 @@
         // direction specified
         process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
 
-        while !state.stack.is_empty() {
-            let node_idx = state.stack.pop().unwrap();
-
+        while let Some(node_idx) = state.stack.pop() {
             // check whether we've visited this node on some previous walk
             if let Some(dup_vec) = &mut dup_vec {
                 if dup_vec[node_idx].is_none() {
@@ -949,8 +916,8 @@
             process_edges(&self.data, &mut state, graph, node_idx, dir);
         }
 
-        let WalkState { result, dup_found, .. } = state;
-        return (result, dup_found);
+        let WalkState { result, dup_found, set, .. } = state;
+        return (result, set, dup_found);
 
         fn process_edges<'tcx>(
             this: &RegionConstraintData<'tcx>,
diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs
index 9c81a11..30af7d0 100644
--- a/src/librustc_infer/infer/mod.rs
+++ b/src/librustc_infer/infer/mod.rs
@@ -20,7 +20,6 @@
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
-use rustc_middle::middle::region;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ConstEvalResult;
 use rustc_middle::traits::select;
@@ -378,22 +377,6 @@
     /// Arose from a subtyping relation
     Subtype(Box<TypeTrace<'tcx>>),
 
-    /// Stack-allocated closures cannot outlive innermost loop
-    /// or function so as to ensure we only require finite stack
-    InfStackClosure(Span),
-
-    /// Invocation of closure must be within its lifetime
-    InvokeClosure(Span),
-
-    /// Dereference of reference must be within its lifetime
-    DerefPointer(Span),
-
-    /// Closure bound must not outlive captured variables
-    ClosureCapture(Span, hir::HirId),
-
-    /// Index into slice must be within its lifetime
-    IndexSlice(Span),
-
     /// When casting `&'a T` to an `&'b Trait` object,
     /// relating `'a` to `'b`
     RelateObjectBound(Span),
@@ -406,10 +389,6 @@
     /// that must outlive some other region.
     RelateRegionParamBound(Span),
 
-    /// A bound placed on type parameters that states that must outlive
-    /// the moment of their instantiation.
-    RelateDefaultParamBound(Span, Ty<'tcx>),
-
     /// Creating a pointer `b` to contents of another reference
     Reborrow(Span),
 
@@ -422,36 +401,9 @@
     /// (&'a &'b T) where a >= b
     ReferenceOutlivesReferent(Ty<'tcx>, Span),
 
-    /// Type or region parameters must be in scope.
-    ParameterInScope(ParameterOrigin, Span),
-
-    /// The type T of an expression E must outlive the lifetime for E.
-    ExprTypeIsNotInScope(Ty<'tcx>, Span),
-
-    /// A `ref b` whose region does not enclose the decl site
-    BindingTypeIsNotValidAtDecl(Span),
-
-    /// Regions appearing in a method receiver must outlive method call
-    CallRcvr(Span),
-
-    /// Regions appearing in a function argument must outlive func call
-    CallArg(Span),
-
     /// Region in return type of invoked fn must enclose call
     CallReturn(Span),
 
-    /// Operands must be in scope
-    Operand(Span),
-
-    /// Region resulting from a `&` expr must enclose the `&` expr
-    AddrOf(Span),
-
-    /// An auto-borrow that does not enclose the expr where it occurs
-    AutoBorrow(Span),
-
-    /// Region constraint arriving from destructor safety
-    SafeDestructor(Span),
-
     /// Comparing the signature and requirements of an impl method against
     /// the containing trait.
     CompareImplMethodObligation {
@@ -1260,7 +1212,6 @@
     pub fn resolve_regions_and_report_errors(
         &self,
         region_context: DefId,
-        region_map: &region::ScopeTree,
         outlives_env: &OutlivesEnvironment<'tcx>,
         mode: RegionckMode,
     ) {
@@ -1280,12 +1231,8 @@
                 .into_infos_and_data()
         };
 
-        let region_rels = &RegionRelations::new(
-            self.tcx,
-            region_context,
-            region_map,
-            outlives_env.free_region_map(),
-        );
+        let region_rels =
+            &RegionRelations::new(self.tcx, region_context, outlives_env.free_region_map());
 
         let (lexical_region_resolutions, errors) =
             lexical_region_resolve::resolve(region_rels, var_infos, data, mode);
@@ -1299,7 +1246,7 @@
             // this infcx was in use.  This is totally hokey but
             // otherwise we have a hard time separating legit region
             // errors from silly ones.
-            self.report_region_errors(region_map, &errors);
+            self.report_region_errors(&errors);
         }
     }
 
@@ -1809,29 +1756,14 @@
     pub fn span(&self) -> Span {
         match *self {
             Subtype(ref a) => a.span(),
-            InfStackClosure(a) => a,
-            InvokeClosure(a) => a,
-            DerefPointer(a) => a,
-            ClosureCapture(a, _) => a,
-            IndexSlice(a) => a,
             RelateObjectBound(a) => a,
             RelateParamBound(a, _) => a,
             RelateRegionParamBound(a) => a,
-            RelateDefaultParamBound(a, _) => a,
             Reborrow(a) => a,
             ReborrowUpvar(a, _) => a,
             DataBorrowed(_, a) => a,
             ReferenceOutlivesReferent(_, a) => a,
-            ParameterInScope(_, a) => a,
-            ExprTypeIsNotInScope(_, a) => a,
-            BindingTypeIsNotValidAtDecl(a) => a,
-            CallRcvr(a) => a,
-            CallArg(a) => a,
             CallReturn(a) => a,
-            Operand(a) => a,
-            AddrOf(a) => a,
-            AutoBorrow(a) => a,
-            SafeDestructor(a) => a,
             CompareImplMethodObligation { span, .. } => span,
         }
     }
diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs
index 289457e..fd3b38e 100644
--- a/src/librustc_infer/infer/outlives/mod.rs
+++ b/src/librustc_infer/infer/outlives/mod.rs
@@ -11,17 +11,17 @@
     param_env: ty::ParamEnv<'tcx>,
 ) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
     debug!("explicit_outlives_bounds()");
-    param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate {
-        ty::Predicate::Projection(..)
-        | ty::Predicate::Trait(..)
-        | ty::Predicate::Subtype(..)
-        | ty::Predicate::WellFormed(..)
-        | ty::Predicate::ObjectSafe(..)
-        | ty::Predicate::ClosureKind(..)
-        | ty::Predicate::TypeOutlives(..)
-        | ty::Predicate::ConstEvaluatable(..)
-        | ty::Predicate::ConstEquate(..) => None,
-        ty::Predicate::RegionOutlives(ref data) => data
+    param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate.kind() {
+        ty::PredicateKind::Projection(..)
+        | ty::PredicateKind::Trait(..)
+        | ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::WellFormed(..)
+        | ty::PredicateKind::ObjectSafe(..)
+        | ty::PredicateKind::ClosureKind(..)
+        | ty::PredicateKind::TypeOutlives(..)
+        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::ConstEquate(..) => None,
+        ty::PredicateKind::RegionOutlives(ref data) => data
             .no_bound_vars()
             .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)),
     })
diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs
index 0c9f002..f45b224 100644
--- a/src/librustc_infer/infer/region_constraints/mod.rs
+++ b/src/librustc_infer/infer/region_constraints/mod.rs
@@ -758,11 +758,9 @@
 
     pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
         match *region {
-            ty::ReScope(..)
-            | ty::ReStatic
-            | ty::ReErased
-            | ty::ReFree(..)
-            | ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT,
+            ty::ReStatic | ty::ReErased | ty::ReFree(..) | ty::ReEarlyBound(..) => {
+                ty::UniverseIndex::ROOT
+            }
             ty::ReEmpty(ui) => ui,
             ty::RePlaceholder(placeholder) => placeholder.universe,
             ty::ReVar(vid) => self.var_universe(vid),
@@ -784,7 +782,7 @@
         )
     }
 
-    /// See [`RegionInference::region_constraints_added_in_snapshot`].
+    /// See `InferCtxt::region_constraints_added_in_snapshot`.
     pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> Option<bool> {
         self.undo_log
             .region_constraints_in_snapshot(mark)
diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs
index 1ec67ef..b51af19 100644
--- a/src/librustc_infer/infer/sub.rs
+++ b/src/librustc_infer/infer/sub.rs
@@ -6,7 +6,7 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::TyVar;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
 use std::mem;
 
 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
@@ -100,11 +100,12 @@
                 self.fields.obligations.push(Obligation::new(
                     self.fields.trace.cause.clone(),
                     self.fields.param_env,
-                    ty::Predicate::Subtype(ty::Binder::dummy(ty::SubtypePredicate {
+                    ty::PredicateKind::Subtype(ty::Binder::dummy(ty::SubtypePredicate {
                         a_is_expected: self.a_is_expected,
                         a,
                         b,
-                    })),
+                    }))
+                    .to_predicate(self.tcx()),
                 ));
 
                 Ok(a)
diff --git a/src/librustc_infer/traits/engine.rs b/src/librustc_infer/traits/engine.rs
index a95257b..2710deb 100644
--- a/src/librustc_infer/traits/engine.rs
+++ b/src/librustc_infer/traits/engine.rs
@@ -33,7 +33,7 @@
                 cause,
                 recursion_depth: 0,
                 param_env,
-                predicate: trait_ref.without_const().to_predicate(),
+                predicate: trait_ref.without_const().to_predicate(infcx.tcx),
             },
         );
     }
diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs
index 8d95904..892a628 100644
--- a/src/librustc_infer/traits/mod.rs
+++ b/src/librustc_infer/traits/mod.rs
@@ -59,7 +59,7 @@
 
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(PredicateObligation<'_>, 112);
+static_assert_size!(PredicateObligation<'_>, 88);
 
 pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
 pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs
index ee903b6..88fc146 100644
--- a/src/librustc_infer/traits/util.rs
+++ b/src/librustc_infer/traits/util.rs
@@ -10,40 +10,49 @@
     tcx: TyCtxt<'tcx>,
     pred: &ty::Predicate<'tcx>,
 ) -> ty::Predicate<'tcx> {
-    match *pred {
-        ty::Predicate::Trait(ref data, constness) => {
-            ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness)
+    match pred.kind() {
+        &ty::PredicateKind::Trait(ref data, constness) => {
+            ty::PredicateKind::Trait(tcx.anonymize_late_bound_regions(data), constness)
+                .to_predicate(tcx)
         }
 
-        ty::Predicate::RegionOutlives(ref data) => {
-            ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data))
+        ty::PredicateKind::RegionOutlives(data) => {
+            ty::PredicateKind::RegionOutlives(tcx.anonymize_late_bound_regions(data))
+                .to_predicate(tcx)
         }
 
-        ty::Predicate::TypeOutlives(ref data) => {
-            ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data))
+        ty::PredicateKind::TypeOutlives(data) => {
+            ty::PredicateKind::TypeOutlives(tcx.anonymize_late_bound_regions(data))
+                .to_predicate(tcx)
         }
 
-        ty::Predicate::Projection(ref data) => {
-            ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data))
+        ty::PredicateKind::Projection(data) => {
+            ty::PredicateKind::Projection(tcx.anonymize_late_bound_regions(data)).to_predicate(tcx)
         }
 
-        ty::Predicate::WellFormed(data) => ty::Predicate::WellFormed(data),
-
-        ty::Predicate::ObjectSafe(data) => ty::Predicate::ObjectSafe(data),
-
-        ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
-            ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind)
+        &ty::PredicateKind::WellFormed(data) => {
+            ty::PredicateKind::WellFormed(data).to_predicate(tcx)
         }
 
-        ty::Predicate::Subtype(ref data) => {
-            ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data))
+        &ty::PredicateKind::ObjectSafe(data) => {
+            ty::PredicateKind::ObjectSafe(data).to_predicate(tcx)
         }
 
-        ty::Predicate::ConstEvaluatable(def_id, substs) => {
-            ty::Predicate::ConstEvaluatable(def_id, substs)
+        &ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
+            ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind).to_predicate(tcx)
         }
 
-        ty::Predicate::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2),
+        ty::PredicateKind::Subtype(data) => {
+            ty::PredicateKind::Subtype(tcx.anonymize_late_bound_regions(data)).to_predicate(tcx)
+        }
+
+        &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
+            ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(tcx)
+        }
+
+        ty::PredicateKind::ConstEquate(c1, c2) => {
+            ty::PredicateKind::ConstEquate(c1, c2).to_predicate(tcx)
+        }
     }
 }
 
@@ -99,14 +108,14 @@
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
 ) -> Elaborator<'tcx> {
-    elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate()))
+    elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate(tcx)))
 }
 
 pub fn elaborate_trait_refs<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
 ) -> Elaborator<'tcx> {
-    let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate());
+    let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate(tcx));
     elaborate_predicates(tcx, predicates)
 }
 
@@ -145,8 +154,8 @@
 
     fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
         let tcx = self.visited.tcx;
-        match obligation.predicate {
-            ty::Predicate::Trait(ref data, _) => {
+        match obligation.predicate.kind() {
+            ty::PredicateKind::Trait(ref data, _) => {
                 // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
@@ -167,36 +176,36 @@
 
                 self.stack.extend(obligations);
             }
-            ty::Predicate::WellFormed(..) => {
+            ty::PredicateKind::WellFormed(..) => {
                 // Currently, we do not elaborate WF predicates,
                 // although we easily could.
             }
-            ty::Predicate::ObjectSafe(..) => {
+            ty::PredicateKind::ObjectSafe(..) => {
                 // Currently, we do not elaborate object-safe
                 // predicates.
             }
-            ty::Predicate::Subtype(..) => {
+            ty::PredicateKind::Subtype(..) => {
                 // Currently, we do not "elaborate" predicates like `X <: Y`,
                 // though conceivably we might.
             }
-            ty::Predicate::Projection(..) => {
+            ty::PredicateKind::Projection(..) => {
                 // Nothing to elaborate in a projection predicate.
             }
-            ty::Predicate::ClosureKind(..) => {
+            ty::PredicateKind::ClosureKind(..) => {
                 // Nothing to elaborate when waiting for a closure's kind to be inferred.
             }
-            ty::Predicate::ConstEvaluatable(..) => {
+            ty::PredicateKind::ConstEvaluatable(..) => {
                 // Currently, we do not elaborate const-evaluatable
                 // predicates.
             }
-            ty::Predicate::ConstEquate(..) => {
+            ty::PredicateKind::ConstEquate(..) => {
                 // Currently, we do not elaborate const-equate
                 // predicates.
             }
-            ty::Predicate::RegionOutlives(..) => {
+            ty::PredicateKind::RegionOutlives(..) => {
                 // Nothing to elaborate from `'a: 'b`.
             }
-            ty::Predicate::TypeOutlives(ref data) => {
+            ty::PredicateKind::TypeOutlives(ref data) => {
                 // We know that `T: 'a` for some type `T`. We can
                 // often elaborate this. For example, if we know that
                 // `[U]: 'a`, that implies that `U: 'a`. Similarly, if
@@ -228,7 +237,7 @@
                                 if r.is_late_bound() {
                                     None
                                 } else {
-                                    Some(ty::Predicate::RegionOutlives(ty::Binder::dummy(
+                                    Some(ty::PredicateKind::RegionOutlives(ty::Binder::dummy(
                                         ty::OutlivesPredicate(r, r_min),
                                     )))
                                 }
@@ -236,7 +245,7 @@
 
                             Component::Param(p) => {
                                 let ty = tcx.mk_ty_param(p.index, p.name);
-                                Some(ty::Predicate::TypeOutlives(ty::Binder::dummy(
+                                Some(ty::PredicateKind::TypeOutlives(ty::Binder::dummy(
                                     ty::OutlivesPredicate(ty, r_min),
                                 )))
                             }
@@ -250,8 +259,9 @@
                                 None
                             }
                         })
-                        .filter(|p| visited.insert(p))
-                        .map(|p| predicate_obligation(p, None)),
+                        .map(|predicate_kind| predicate_kind.to_predicate(tcx))
+                        .filter(|predicate| visited.insert(predicate))
+                        .map(|predicate| predicate_obligation(predicate, None)),
                 );
             }
         }
@@ -317,7 +327,7 @@
 
     fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
         while let Some(obligation) = self.base_iterator.next() {
-            if let ty::Predicate::Trait(data, _) = obligation.predicate {
+            if let ty::PredicateKind::Trait(data, _) = obligation.predicate.kind() {
                 return Some(data.to_poly_trait_ref());
             }
         }
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 801c8e9..214701d 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -7,7 +7,7 @@
 use rustc_ast::{self, ast, visit};
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_data_structures::sync::{par_iter, Lrc, Once, ParallelIterator, WorkerLocal};
+use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
 use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
 use rustc_errors::{ErrorReported, PResult};
 use rustc_expand::base::ExtCtxt;
@@ -169,10 +169,10 @@
     sess.init_features(features);
 
     let crate_types = util::collect_crate_types(sess, &krate.attrs);
-    sess.crate_types.set(crate_types);
+    sess.init_crate_types(crate_types);
 
     let disambiguator = util::compute_crate_disambiguator(sess);
-    sess.crate_disambiguator.set(disambiguator);
+    sess.crate_disambiguator.set(disambiguator).expect("not yet initialized");
     rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
 
     if sess.opts.incremental.is_some() {
@@ -244,7 +244,7 @@
             alt_std_name,
         );
         if let Some(name) = name {
-            sess.parse_sess.injected_crate_name.set(name);
+            sess.parse_sess.injected_crate_name.set(name).expect("not yet initialized");
         }
         krate
     });
@@ -288,7 +288,7 @@
         let features = sess.features_untracked();
         let cfg = rustc_expand::expand::ExpansionConfig {
             features: Some(&features),
-            recursion_limit: *sess.recursion_limit.get(),
+            recursion_limit: sess.recursion_limit(),
             trace_mac: sess.opts.debugging_opts.trace_macros,
             should_test: sess.opts.test,
             ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
@@ -358,7 +358,7 @@
         rustc_ast_passes::ast_validation::check_crate(sess, &krate, &mut resolver.lint_buffer())
     });
 
-    let crate_types = sess.crate_types.borrow();
+    let crate_types = sess.crate_types();
     let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
 
     // For backwards compatibility, we don't try to run proc macro injection
@@ -488,7 +488,7 @@
             // If the filename has been overridden using `-o`, it will not be modified
             // by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
             OutputType::Exe if !exact_name => {
-                for crate_type in sess.crate_types.borrow().iter() {
+                for crate_type in sess.crate_types().iter() {
                     let p = filename_for_input(sess, *crate_type, crate_name, outputs);
                     out_filenames.push(p);
                 }
@@ -721,7 +721,7 @@
     mut resolver_outputs: ResolverOutputs,
     outputs: OutputFilenames,
     crate_name: &str,
-    global_ctxt: &'tcx Once<GlobalCtxt<'tcx>>,
+    global_ctxt: &'tcx OnceCell<GlobalCtxt<'tcx>>,
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
 ) -> QueryContext<'tcx> {
     let sess = &compiler.session();
@@ -743,7 +743,7 @@
     }
 
     let gcx = sess.time("setup_global_ctxt", || {
-        global_ctxt.init_locking(|| {
+        global_ctxt.get_or_init(|| {
             TyCtxt::create_global_ctxt(
                 sess,
                 lint_store,
@@ -905,8 +905,7 @@
 
     let metadata_kind = tcx
         .sess
-        .crate_types
-        .borrow()
+        .crate_types()
         .iter()
         .map(|ty| match *ty {
             CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None,
diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs
index 94cd4bc..283be16 100644
--- a/src/librustc_interface/queries.rs
+++ b/src/librustc_interface/queries.rs
@@ -3,7 +3,7 @@
 
 use rustc_ast::{self, ast};
 use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
+use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_hir::Crate;
@@ -65,7 +65,7 @@
 
 pub struct Queries<'tcx> {
     compiler: &'tcx Compiler,
-    gcx: Once<GlobalCtxt<'tcx>>,
+    gcx: OnceCell<GlobalCtxt<'tcx>>,
 
     arena: WorkerLocal<Arena<'tcx>>,
     hir_arena: WorkerLocal<rustc_ast_lowering::Arena<'tcx>>,
@@ -86,7 +86,7 @@
     pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> {
         Queries {
             compiler,
-            gcx: Once::new(),
+            gcx: OnceCell::new(),
             arena: WorkerLocal::new(|_| Arena::default()),
             hir_arena: WorkerLocal::new(|_| rustc_ast_lowering::Arena::default()),
             dep_graph_future: Default::default(),
diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs
index 5e17660..0394821 100644
--- a/src/librustc_interface/tests.rs
+++ b/src/librustc_interface/tests.rs
@@ -2,7 +2,6 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
-use rustc_middle::middle::cstore;
 use rustc_session::config::Strip;
 use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
 use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
@@ -11,6 +10,7 @@
 use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
+use rustc_session::utils::NativeLibKind;
 use rustc_session::{build_session, Session};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
@@ -300,30 +300,30 @@
 
     // Reference
     v1.libs = vec![
-        (String::from("a"), None, Some(cstore::NativeStatic)),
-        (String::from("b"), None, Some(cstore::NativeFramework)),
-        (String::from("c"), None, Some(cstore::NativeUnknown)),
+        (String::from("a"), None, NativeLibKind::StaticBundle),
+        (String::from("b"), None, NativeLibKind::Framework),
+        (String::from("c"), None, NativeLibKind::Unspecified),
     ];
 
     // Change label
     v2.libs = vec![
-        (String::from("a"), None, Some(cstore::NativeStatic)),
-        (String::from("X"), None, Some(cstore::NativeFramework)),
-        (String::from("c"), None, Some(cstore::NativeUnknown)),
+        (String::from("a"), None, NativeLibKind::StaticBundle),
+        (String::from("X"), None, NativeLibKind::Framework),
+        (String::from("c"), None, NativeLibKind::Unspecified),
     ];
 
     // Change kind
     v3.libs = vec![
-        (String::from("a"), None, Some(cstore::NativeStatic)),
-        (String::from("b"), None, Some(cstore::NativeStatic)),
-        (String::from("c"), None, Some(cstore::NativeUnknown)),
+        (String::from("a"), None, NativeLibKind::StaticBundle),
+        (String::from("b"), None, NativeLibKind::StaticBundle),
+        (String::from("c"), None, NativeLibKind::Unspecified),
     ];
 
     // Change new-name
     v4.libs = vec![
-        (String::from("a"), None, Some(cstore::NativeStatic)),
-        (String::from("b"), Some(String::from("X")), Some(cstore::NativeFramework)),
-        (String::from("c"), None, Some(cstore::NativeUnknown)),
+        (String::from("a"), None, NativeLibKind::StaticBundle),
+        (String::from("b"), Some(String::from("X")), NativeLibKind::Framework),
+        (String::from("c"), None, NativeLibKind::Unspecified),
     ];
 
     assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
@@ -345,21 +345,21 @@
 
     // Reference
     v1.libs = vec![
-        (String::from("a"), None, Some(cstore::NativeStatic)),
-        (String::from("b"), None, Some(cstore::NativeFramework)),
-        (String::from("c"), None, Some(cstore::NativeUnknown)),
+        (String::from("a"), None, NativeLibKind::StaticBundle),
+        (String::from("b"), None, NativeLibKind::Framework),
+        (String::from("c"), None, NativeLibKind::Unspecified),
     ];
 
     v2.libs = vec![
-        (String::from("b"), None, Some(cstore::NativeFramework)),
-        (String::from("a"), None, Some(cstore::NativeStatic)),
-        (String::from("c"), None, Some(cstore::NativeUnknown)),
+        (String::from("b"), None, NativeLibKind::Framework),
+        (String::from("a"), None, NativeLibKind::StaticBundle),
+        (String::from("c"), None, NativeLibKind::Unspecified),
     ];
 
     v3.libs = vec![
-        (String::from("c"), None, Some(cstore::NativeUnknown)),
-        (String::from("a"), None, Some(cstore::NativeStatic)),
-        (String::from("b"), None, Some(cstore::NativeFramework)),
+        (String::from("c"), None, NativeLibKind::Unspecified),
+        (String::from("a"), None, NativeLibKind::StaticBundle),
+        (String::from("b"), None, NativeLibKind::Framework),
     ];
 
     assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 5a76802..a15da94 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -406,7 +406,7 @@
 
     // Also incorporate crate type, so that we don't get symbol conflicts when
     // linking against a library of the same name, if this is an executable.
-    let is_exe = session.crate_types.borrow().contains(&CrateType::Executable);
+    let is_exe = session.crate_types().contains(&CrateType::Executable);
     hasher.write(if is_exe { b"exe" } else { b"lib" });
 
     CrateDisambiguator::from(hasher.finish::<Fingerprint>())
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index bca91fb..e17e8b7 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1202,13 +1202,13 @@
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'tcx>) {
         use rustc_middle::ty::fold::TypeFoldable;
-        use rustc_middle::ty::Predicate::*;
+        use rustc_middle::ty::PredicateKind::*;
 
         if cx.tcx.features().trivial_bounds {
             let def_id = cx.tcx.hir().local_def_id(item.hir_id);
             let predicates = cx.tcx.predicates_of(def_id);
             for &(predicate, span) in predicates.predicates {
-                let predicate_kind_name = match predicate {
+                let predicate_kind_name = match predicate.kind() {
                     Trait(..) => "Trait",
                     TypeOutlives(..) |
                     RegionOutlives(..) => "Lifetime",
@@ -1497,8 +1497,8 @@
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
             .iter()
-            .filter_map(|(pred, _)| match pred {
-                ty::Predicate::RegionOutlives(outlives) => {
+            .filter_map(|(pred, _)| match pred.kind() {
+                ty::PredicateKind::RegionOutlives(outlives) => {
                     let outlives = outlives.skip_binder();
                     match outlives.0 {
                         ty::ReEarlyBound(ebr) if ebr.index == index => Some(outlives.1),
@@ -1516,8 +1516,8 @@
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
             .iter()
-            .filter_map(|(pred, _)| match pred {
-                ty::Predicate::TypeOutlives(outlives) => {
+            .filter_map(|(pred, _)| match pred.kind() {
+                ty::PredicateKind::TypeOutlives(outlives) => {
                     let outlives = outlives.skip_binder();
                     outlives.0.is_param(index).then_some(outlives.1)
                 }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index c24079a..dea82934 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -146,7 +146,9 @@
                 ty::Opaque(def, _) => {
                     let mut has_emitted = false;
                     for (predicate, _) in cx.tcx.predicates_of(def).predicates {
-                        if let ty::Predicate::Trait(ref poly_trait_predicate, _) = predicate {
+                        if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) =
+                            predicate.kind()
+                        {
                             let trait_ref = poly_trait_predicate.skip_binder().trait_ref;
                             let def_id = trait_ref.def_id;
                             let descr_pre =
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index a9e7a9f..b0220dd 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -615,7 +615,7 @@
     fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         // If we're only compiling an rlib, then there's no need to select a
         // panic runtime, so we just skip this section entirely.
-        let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| *ct != CrateType::Rlib);
+        let any_non_rlib = self.sess.crate_types().iter().any(|ct| *ct != CrateType::Rlib);
         if !any_non_rlib {
             info!("panic runtime injection skipped, only generating rlib");
             return;
@@ -734,7 +734,7 @@
         // At this point we've determined that we need an allocator. Let's see
         // if our compilation session actually needs an allocator based on what
         // we're emitting.
-        let all_rlib = self.sess.crate_types.borrow().iter().all(|ct| match *ct {
+        let all_rlib = self.sess.crate_types().iter().all(|ct| match *ct {
             CrateType::Rlib => true,
             _ => false,
         });
diff --git a/src/librustc_metadata/dependency_format.rs b/src/librustc_metadata/dependency_format.rs
index 0876cd1..aa5fafc 100644
--- a/src/librustc_metadata/dependency_format.rs
+++ b/src/librustc_metadata/dependency_format.rs
@@ -64,8 +64,7 @@
 
 crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
     tcx.sess
-        .crate_types
-        .borrow()
+        .crate_types()
         .iter()
         .map(|&ty| {
             let linkage = calculate_type(tcx, ty);
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index f78f3c5..5a4862d 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -670,7 +670,7 @@
 
         // The all loop is because `--crate-type=rlib --crate-type=rlib` is
         // legal and produces both inside this type.
-        let is_rlib = self.sess.crate_types.borrow().iter().all(|c| *c == CrateType::Rlib);
+        let is_rlib = self.sess.crate_types().iter().all(|c| *c == CrateType::Rlib);
         let needs_object_code = self.sess.opts.output_types.should_codegen();
         // If we're producing an rlib, then we don't need object code.
         // Or, if we're not producing object code, then we don't need it either
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
index 51c9950..fc4235a 100644
--- a/src/librustc_metadata/native_libs.rs
+++ b/src/librustc_metadata/native_libs.rs
@@ -3,22 +3,23 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::middle::cstore::{self, NativeLibrary};
+use rustc_middle::middle::cstore::NativeLib;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
+use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
-crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLibrary> {
+crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
     let mut collector = Collector { tcx, libs: Vec::new() };
     tcx.hir().krate().visit_all_item_likes(&mut collector);
     collector.process_command_line();
     collector.libs
 }
 
-crate fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
+crate fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
     match lib.cfg {
         Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
         None => true,
@@ -27,7 +28,7 @@
 
 struct Collector<'tcx> {
     tcx: TyCtxt<'tcx>,
-    libs: Vec<NativeLibrary>,
+    libs: Vec<NativeLib>,
 }
 
 impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
@@ -47,9 +48,9 @@
                 Some(item) => item,
                 None => continue,
             };
-            let mut lib = NativeLibrary {
+            let mut lib = NativeLib {
                 name: None,
-                kind: cstore::NativeUnknown,
+                kind: NativeLibKind::Unspecified,
                 cfg: None,
                 foreign_module: Some(self.tcx.hir().local_def_id(it.hir_id).to_def_id()),
                 wasm_import_module: None,
@@ -64,11 +65,11 @@
                         None => continue, // skip like historical compilers
                     };
                     lib.kind = match &*kind.as_str() {
-                        "static" => cstore::NativeStatic,
-                        "static-nobundle" => cstore::NativeStaticNobundle,
-                        "dylib" => cstore::NativeUnknown,
-                        "framework" => cstore::NativeFramework,
-                        "raw-dylib" => cstore::NativeRawDylib,
+                        "static" => NativeLibKind::StaticBundle,
+                        "static-nobundle" => NativeLibKind::StaticNoBundle,
+                        "dylib" => NativeLibKind::Dylib,
+                        "framework" => NativeLibKind::Framework,
+                        "raw-dylib" => NativeLibKind::RawDylib,
                         k => {
                             struct_span_err!(
                                 self.tcx.sess,
@@ -80,7 +81,7 @@
                             .span_label(item.span(), "unknown kind")
                             .span_label(m.span, "")
                             .emit();
-                            cstore::NativeUnknown
+                            NativeLibKind::Unspecified
                         }
                     };
                 } else if item.check_name(sym::name) {
@@ -134,7 +135,7 @@
 }
 
 impl Collector<'tcx> {
-    fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
+    fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
         if lib.name.as_ref().map(|&s| s == kw::Invalid).unwrap_or(false) {
             match span {
                 Some(span) => {
@@ -154,7 +155,7 @@
             return;
         }
         let is_osx = self.tcx.sess.target.target.options.is_like_osx;
-        if lib.kind == cstore::NativeFramework && !is_osx {
+        if lib.kind == NativeLibKind::Framework && !is_osx {
             let msg = "native frameworks are only available on macOS targets";
             match span {
                 Some(span) => struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(),
@@ -170,7 +171,7 @@
             )
             .emit();
         }
-        if lib.kind == cstore::NativeStaticNobundle && !self.tcx.features().static_nobundle {
+        if lib.kind == NativeLibKind::StaticNoBundle && !self.tcx.features().static_nobundle {
             feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::static_nobundle,
@@ -179,7 +180,7 @@
             )
             .emit();
         }
-        if lib.kind == cstore::NativeRawDylib && !self.tcx.features().raw_dylib {
+        if lib.kind == NativeLibKind::RawDylib && !self.tcx.features().raw_dylib {
             feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::raw_dylib,
@@ -240,8 +241,8 @@
                 .drain_filter(|lib| {
                     if let Some(lib_name) = lib.name {
                         if lib_name.as_str() == *name {
-                            if let Some(k) = kind {
-                                lib.kind = k;
+                            if kind != NativeLibKind::Unspecified {
+                                lib.kind = kind;
                             }
                             if let &Some(ref new_name) = new_name {
                                 lib.name = Some(Symbol::intern(new_name));
@@ -255,9 +256,9 @@
             if existing.is_empty() {
                 // Add if not found
                 let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
-                let lib = NativeLibrary {
+                let lib = NativeLib {
                     name: Some(Symbol::intern(new_name.unwrap_or(name))),
-                    kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
+                    kind,
                     cfg: None,
                     foreign_module: None,
                     wasm_import_module: None,
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 32149c0..2b292b3 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -10,7 +10,7 @@
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, Once};
+use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, OnceCell};
 use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive};
 use rustc_hir as hir;
@@ -23,7 +23,7 @@
 use rustc_middle::dep_graph::{self, DepNode, DepNodeExt, DepNodeIndex};
 use rustc_middle::hir::exports::Export;
 use rustc_middle::middle::cstore::{CrateSource, ExternCrate};
-use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLibrary};
+use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, interpret, Body, Promoted};
@@ -79,7 +79,7 @@
     /// Proc macro descriptions for this crate, if it's a proc macro crate.
     raw_proc_macros: Option<&'static [ProcMacro]>,
     /// Source maps for code from the crate.
-    source_map_import_info: Once<Vec<ImportedSourceFile>>,
+    source_map_import_info: OnceCell<Vec<ImportedSourceFile>>,
     /// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
     alloc_decoding_state: AllocDecodingState,
     /// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
@@ -1278,7 +1278,7 @@
         })
     }
 
-    fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
+    fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLib> {
         if self.root.is_proc_macro_crate() {
             // Proc macro crates do not have any *target* native libraries.
             vec![]
@@ -1486,7 +1486,7 @@
             }
         };
 
-        self.cdata.source_map_import_info.init_locking(|| {
+        self.cdata.source_map_import_info.get_or_init(|| {
             let external_source_map = self.root.source_map.decode(self);
 
             external_source_map
@@ -1600,7 +1600,7 @@
             def_path_table,
             trait_impls,
             raw_proc_macros,
-            source_map_import_info: Once::new(),
+            source_map_import_info: OnceCell::new(),
             alloc_decoding_state,
             dep_node_index: AtomicCell::new(DepNodeIndex::INVALID),
             cnum,
diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
index b182726..1b168bf 100644
--- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
+++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
@@ -13,12 +13,13 @@
 use rustc_hir::definitions::DefPathTable;
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_middle::hir::exports::Export;
-use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata, NativeLibraryKind};
+use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata};
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::middle::stability::DeprecationEntry;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::query::QueryConfig;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_session::utils::NativeLibKind;
 use rustc_session::{CrateDisambiguator, Session};
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{Ident, Symbol};
@@ -246,11 +247,13 @@
     // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
-            Some(NativeLibraryKind::NativeUnknown | NativeLibraryKind::NativeRawDylib) => true,
+            Some(NativeLibKind::Dylib | NativeLibKind::RawDylib | NativeLibKind::Unspecified) => {
+                true
+            }
             _ => false,
         },
         is_statically_included_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
-            Some(NativeLibraryKind::NativeStatic | NativeLibraryKind::NativeStaticNobundle) => true,
+            Some(NativeLibKind::StaticBundle | NativeLibKind::StaticNoBundle) => true,
             _ => false,
         },
         native_library_kind: |tcx, id| {
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index 2589e16..91fbfcc 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -18,9 +18,7 @@
 use rustc_hir::{AnonConst, GenericParamKind};
 use rustc_index::vec::Idx;
 use rustc_middle::hir::map::Map;
-use rustc_middle::middle::cstore::{
-    EncodedMetadata, ForeignModule, LinkagePreference, NativeLibrary,
-};
+use rustc_middle::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
@@ -418,7 +416,7 @@
     }
 
     fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
-        let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
+        let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro);
 
         let mut i = self.position();
 
@@ -1355,7 +1353,7 @@
         self.encode_promoted_mir(def_id);
     }
 
-    fn encode_native_libraries(&mut self) -> Lazy<[NativeLibrary]> {
+    fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> {
         let used_libraries = self.tcx.native_libraries(LOCAL_CRATE);
         self.lazy(used_libraries.iter().cloned())
     }
@@ -1366,7 +1364,7 @@
     }
 
     fn encode_proc_macros(&mut self) -> Option<Lazy<[DefIndex]>> {
-        let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
+        let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro);
         if is_proc_macro {
             let tcx = self.tcx;
             Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index)))
diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs
index 6693076..89d525e 100644
--- a/src/librustc_metadata/rmeta/mod.rs
+++ b/src/librustc_metadata/rmeta/mod.rs
@@ -11,7 +11,7 @@
 use rustc_hir::lang_items;
 use rustc_index::vec::IndexVec;
 use rustc_middle::hir::exports::Export;
-use rustc_middle::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLibrary};
+use rustc_middle::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, ReprOptions, Ty};
@@ -190,7 +190,7 @@
     lang_items: Lazy<[(DefIndex, usize)]>,
     lang_items_missing: Lazy<[lang_items::LangItem]>,
     diagnostic_items: Lazy<[(Symbol, DefIndex)]>,
-    native_libraries: Lazy<[NativeLibrary]>,
+    native_libraries: Lazy<[NativeLib]>,
     foreign_modules: Lazy<[ForeignModule]>,
     source_map: Lazy<[rustc_span::SourceFile]>,
     def_path_table: Lazy<rustc_hir::definitions::DefPathTable>,
diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs
index a97db31..2df878c 100644
--- a/src/librustc_middle/arena.rs
+++ b/src/librustc_middle/arena.rs
@@ -76,6 +76,12 @@
             [few] hir_definitions: rustc_hir::definitions::Definitions,
             [] hir_owner: rustc_middle::hir::Owner<$tcx>,
             [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,
+
+            // Note that this deliberately duplicates items in the `rustc_hir::arena`,
+            // since we need to allocate this type on both the `rustc_hir` arena
+            // (during lowering) and the `librustc_middle` arena (for decoding MIR)
+            [decode] asm_template: rustc_ast::ast::InlineAsmTemplatePiece,
+
         ], $tcx);
     )
 }
diff --git a/src/librustc_middle/ich/impls_ty.rs b/src/librustc_middle/ich/impls_ty.rs
index 377c866..ef62478 100644
--- a/src/librustc_middle/ich/impls_ty.rs
+++ b/src/librustc_middle/ich/impls_ty.rs
@@ -87,9 +87,6 @@
                 index.hash_stable(hcx, hasher);
                 name.hash_stable(hcx, hasher);
             }
-            ty::ReScope(scope) => {
-                scope.hash_stable(hcx, hasher);
-            }
             ty::ReFree(ref free_region) => {
                 free_region.hash_stable(hcx, hasher);
             }
diff --git a/src/librustc_middle/middle/cstore.rs b/src/librustc_middle/middle/cstore.rs
index 012390e..97e877d 100644
--- a/src/librustc_middle/middle/cstore.rs
+++ b/src/librustc_middle/middle/cstore.rs
@@ -2,8 +2,6 @@
 //! are *mostly* used as a part of that interface, but these should
 //! probably get a better home if someone can find one.
 
-pub use self::NativeLibraryKind::*;
-
 use crate::ty::TyCtxt;
 
 use rustc_ast::ast;
@@ -14,7 +12,7 @@
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, DefPathTable};
 use rustc_macros::HashStable;
 use rustc_session::search_paths::PathKind;
-pub use rustc_session::utils::NativeLibraryKind;
+use rustc_session::utils::NativeLibKind;
 use rustc_session::CrateDisambiguator;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -89,8 +87,8 @@
 }
 
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
-pub struct NativeLibrary {
-    pub kind: NativeLibraryKind,
+pub struct NativeLib {
+    pub kind: NativeLibKind,
     pub name: Option<Symbol>,
     pub cfg: Option<ast::MetaItem>,
     pub foreign_module: Option<DefId>,
diff --git a/src/librustc_middle/middle/limits.rs b/src/librustc_middle/middle/limits.rs
index c43c22c..19c0569 100644
--- a/src/librustc_middle/middle/limits.rs
+++ b/src/librustc_middle/middle/limits.rs
@@ -7,7 +7,7 @@
 
 use crate::bug;
 use rustc_ast::ast;
-use rustc_data_structures::sync::Once;
+use rustc_data_structures::sync::OnceCell;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 
@@ -22,7 +22,7 @@
 fn update_limit(
     sess: &Session,
     krate: &ast::Crate,
-    limit: &Once<usize>,
+    limit: &OnceCell<usize>,
     name: Symbol,
     default: usize,
 ) {
@@ -34,7 +34,7 @@
         if let Some(s) = attr.value_str() {
             match s.as_str().parse() {
                 Ok(n) => {
-                    limit.set(n);
+                    limit.set(n).unwrap();
                     return;
                 }
                 Err(e) => {
@@ -62,5 +62,5 @@
             }
         }
     }
-    limit.set(default);
+    limit.set(default).unwrap();
 }
diff --git a/src/librustc_middle/middle/region.rs b/src/librustc_middle/middle/region.rs
index f02d8fe..943a065 100644
--- a/src/librustc_middle/middle/region.rs
+++ b/src/librustc_middle/middle/region.rs
@@ -7,7 +7,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
 
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
-use crate::ty::{self, DefIdTree, TyCtxt};
+use crate::ty::TyCtxt;
 use rustc_hir as hir;
 use rustc_hir::Node;
 
@@ -333,7 +333,7 @@
     pub source: hir::YieldSource,
 }
 
-impl<'tcx> ScopeTree {
+impl ScopeTree {
     pub fn record_scope_parent(&mut self, child: Scope, parent: Option<(Scope, ScopeDepth)>) {
         debug!("{:?}.parent = {:?}", child, parent);
 
@@ -348,24 +348,6 @@
         }
     }
 
-    pub fn each_encl_scope<E>(&self, mut e: E)
-    where
-        E: FnMut(Scope, Scope),
-    {
-        for (&child, &parent) in &self.parent_map {
-            e(child, parent.0)
-        }
-    }
-
-    pub fn each_var_scope<E>(&self, mut e: E)
-    where
-        E: FnMut(&hir::ItemLocalId, Scope),
-    {
-        for (child, &parent) in self.var_map.iter() {
-            e(child, parent)
-        }
-    }
-
     pub fn opt_destruction_scope(&self, n: hir::ItemLocalId) -> Option<Scope> {
         self.destruction_scopes.get(&n).cloned()
     }
@@ -406,12 +388,6 @@
         self.parent_map.get(&id).cloned().map(|(p, _)| p)
     }
 
-    /// Returns the narrowest scope that encloses `id`, if any.
-    #[allow(dead_code)] // used in cfg
-    pub fn encl_scope(&self, id: Scope) -> Scope {
-        self.opt_encl_scope(id).unwrap()
-    }
-
     /// Returns the lifetime of the local variable `var_id`
     pub fn var_scope(&self, var_id: hir::ItemLocalId) -> Scope {
         self.var_map
@@ -448,17 +424,6 @@
         None
     }
 
-    /// Returns the lifetime of the variable `id`.
-    pub fn var_region(&self, id: hir::ItemLocalId) -> ty::RegionKind {
-        let scope = ty::ReScope(self.var_scope(id));
-        debug!("var_region({:?}) = {:?}", id, scope);
-        scope
-    }
-
-    pub fn scopes_intersect(&self, scope1: Scope, scope2: Scope) -> bool {
-        self.is_subscope_of(scope1, scope2) || self.is_subscope_of(scope2, scope1)
-    }
-
     /// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and
     /// `false` otherwise.
     pub fn is_subscope_of(&self, subscope: Scope, superscope: Scope) -> bool {
@@ -479,127 +444,6 @@
         true
     }
 
-    /// Returns the ID of the innermost containing body.
-    pub fn containing_body(&self, mut scope: Scope) -> Option<hir::ItemLocalId> {
-        loop {
-            if let ScopeData::CallSite = scope.data {
-                return Some(scope.item_local_id());
-            }
-
-            scope = self.opt_encl_scope(scope)?;
-        }
-    }
-
-    /// Finds the nearest common ancestor of two scopes. That is, finds the
-    /// smallest scope which is greater than or equal to both `scope_a` and
-    /// `scope_b`.
-    pub fn nearest_common_ancestor(&self, scope_a: Scope, scope_b: Scope) -> Scope {
-        if scope_a == scope_b {
-            return scope_a;
-        }
-
-        let mut a = scope_a;
-        let mut b = scope_b;
-
-        // Get the depth of each scope's parent. If either scope has no parent,
-        // it must be the root, which means we can stop immediately because the
-        // root must be the nearest common ancestor. (In practice, this is
-        // moderately common.)
-        let (parent_a, parent_a_depth) = match self.parent_map.get(&a) {
-            Some(pd) => *pd,
-            None => return a,
-        };
-        let (parent_b, parent_b_depth) = match self.parent_map.get(&b) {
-            Some(pd) => *pd,
-            None => return b,
-        };
-
-        if parent_a_depth > parent_b_depth {
-            // `a` is lower than `b`. Move `a` up until it's at the same depth
-            // as `b`. The first move up is trivial because we already found
-            // `parent_a` above; the loop does the remaining N-1 moves.
-            a = parent_a;
-            for _ in 0..(parent_a_depth - parent_b_depth - 1) {
-                a = self.parent_map.get(&a).unwrap().0;
-            }
-        } else if parent_b_depth > parent_a_depth {
-            // `b` is lower than `a`.
-            b = parent_b;
-            for _ in 0..(parent_b_depth - parent_a_depth - 1) {
-                b = self.parent_map.get(&b).unwrap().0;
-            }
-        } else {
-            // Both scopes are at the same depth, and we know they're not equal
-            // because that case was tested for at the top of this function. So
-            // we can trivially move them both up one level now.
-            assert!(parent_a_depth != 0);
-            a = parent_a;
-            b = parent_b;
-        }
-
-        // Now both scopes are at the same level. We move upwards in lockstep
-        // until they match. In practice, this loop is almost always executed
-        // zero times because `a` is almost always a direct ancestor of `b` or
-        // vice versa.
-        while a != b {
-            a = self.parent_map.get(&a).unwrap().0;
-            b = self.parent_map.get(&b).unwrap().0;
-        }
-
-        a
-    }
-
-    /// Assuming that the provided region was defined within this `ScopeTree`,
-    /// returns the outermost `Scope` that the region outlives.
-    pub fn early_free_scope(&self, tcx: TyCtxt<'tcx>, br: &ty::EarlyBoundRegion) -> Scope {
-        let param_owner = tcx.parent(br.def_id).unwrap();
-
-        let param_owner_id = tcx.hir().as_local_hir_id(param_owner.expect_local());
-        let scope = tcx
-            .hir()
-            .maybe_body_owned_by(param_owner_id)
-            .map(|body_id| tcx.hir().body(body_id).value.hir_id.local_id)
-            .unwrap_or_else(|| {
-                // The lifetime was defined on node that doesn't own a body,
-                // which in practice can only mean a trait or an impl, that
-                // is the parent of a method, and that is enforced below.
-                if Some(param_owner_id) != self.root_parent {
-                    tcx.sess.delay_span_bug(
-                        DUMMY_SP,
-                        &format!(
-                            "free_scope: {:?} not recognized by the \
-                              region scope tree for {:?} / {:?}",
-                            param_owner,
-                            self.root_parent.map(|id| tcx.hir().local_def_id(id)),
-                            self.root_body.map(|hir_id| hir_id.owner)
-                        ),
-                    );
-                }
-
-                // The trait/impl lifetime is in scope for the method's body.
-                self.root_body.unwrap().local_id
-            });
-
-        Scope { id: scope, data: ScopeData::CallSite }
-    }
-
-    /// Assuming that the provided region was defined within this `ScopeTree`,
-    /// returns the outermost `Scope` that the region outlives.
-    pub fn free_scope(&self, tcx: TyCtxt<'tcx>, fr: &ty::FreeRegion) -> Scope {
-        let param_owner = match fr.bound_region {
-            ty::BoundRegion::BrNamed(def_id, _) => tcx.parent(def_id).unwrap(),
-            _ => fr.scope,
-        };
-
-        // Ensure that the named late-bound lifetimes were defined
-        // on the same function that they ended up being freed in.
-        assert_eq!(param_owner, fr.scope);
-
-        let param_owner_id = tcx.hir().as_local_hir_id(param_owner.expect_local());
-        let body_id = tcx.hir().body_owned_by(param_owner_id);
-        Scope { id: tcx.hir().body(body_id).value.hir_id.local_id, data: ScopeData::CallSite }
-    }
-
     /// Checks whether the given scope contains a `yield`. If so,
     /// returns `Some((span, expr_count))` with the span of a yield we found and
     /// the number of expressions and patterns appearing before the `yield` in the body + 1.
diff --git a/src/librustc_middle/mir/interpret/allocation.rs b/src/librustc_middle/mir/interpret/allocation.rs
index 2b6cf22..96195db 100644
--- a/src/librustc_middle/mir/interpret/allocation.rs
+++ b/src/librustc_middle/mir/interpret/allocation.rs
@@ -11,6 +11,7 @@
 
 use super::{
     read_target_uint, write_target_uint, AllocId, InterpResult, Pointer, Scalar, ScalarMaybeUninit,
+    UninitBytesAccess,
 };
 
 #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
@@ -545,17 +546,23 @@
 impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// Checks whether the given range  is entirely defined.
     ///
-    /// Returns `Ok(())` if it's defined. Otherwise returns the index of the byte
-    /// at which the first undefined access begins.
-    fn is_defined(&self, ptr: Pointer<Tag>, size: Size) -> Result<(), Size> {
+    /// Returns `Ok(())` if it's defined. Otherwise returns the range of byte
+    /// indexes of the first contiguous undefined access.
+    fn is_defined(&self, ptr: Pointer<Tag>, size: Size) -> Result<(), Range<Size>> {
         self.init_mask.is_range_initialized(ptr.offset, ptr.offset + size) // `Size` addition
     }
 
-    /// Checks that a range of bytes is defined. If not, returns the `ReadUndefBytes`
-    /// error which will report the first byte which is undefined.
+    /// Checks that a range of bytes is defined. If not, returns the `InvalidUndefBytes`
+    /// error which will report the first range of bytes which is undefined.
     fn check_defined(&self, ptr: Pointer<Tag>, size: Size) -> InterpResult<'tcx> {
-        self.is_defined(ptr, size)
-            .or_else(|idx| throw_ub!(InvalidUninitBytes(Some(Pointer::new(ptr.alloc_id, idx)))))
+        self.is_defined(ptr, size).or_else(|idx_range| {
+            throw_ub!(InvalidUninitBytes(Some(Box::new(UninitBytesAccess {
+                access_ptr: ptr.erase_tag(),
+                access_size: size,
+                uninit_ptr: Pointer::new(ptr.alloc_id, idx_range.start),
+                uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
+            }))))
+        })
     }
 
     pub fn mark_definedness(&mut self, ptr: Pointer<Tag>, size: Size, new_state: bool) {
@@ -758,19 +765,25 @@
 
     /// Checks whether the range `start..end` (end-exclusive) is entirely initialized.
     ///
-    /// Returns `Ok(())` if it's initialized. Otherwise returns the index of the byte
-    /// at which the first uninitialized access begins.
+    /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte
+    /// indexes for the first contiguous span of the uninitialized access.
     #[inline]
-    pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Size> {
+    pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Range<Size>> {
         if end > self.len {
-            return Err(self.len);
+            return Err(self.len..end);
         }
 
         // FIXME(oli-obk): optimize this for allocations larger than a block.
         let idx = (start.bytes()..end.bytes()).map(Size::from_bytes).find(|&i| !self.get(i));
 
         match idx {
-            Some(idx) => Err(idx),
+            Some(idx) => {
+                let undef_end = (idx.bytes()..end.bytes())
+                    .map(Size::from_bytes)
+                    .find(|&i| self.get(i))
+                    .unwrap_or(end);
+                Err(idx..undef_end)
+            }
             None => Ok(()),
         }
     }
diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs
index 06fe379..d32a147 100644
--- a/src/librustc_middle/mir/interpret/error.rs
+++ b/src/librustc_middle/mir/interpret/error.rs
@@ -6,7 +6,7 @@
 use crate::ty::{self, layout, tls, FnSig, Ty};
 
 use rustc_data_structures::sync::Lock;
-use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorReported};
+use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::definitions::DefPathData;
 use rustc_macros::HashStable;
@@ -327,6 +327,19 @@
     }
 }
 
+/// Details of an access to uninitialized bytes where it is not allowed.
+#[derive(Debug)]
+pub struct UninitBytesAccess {
+    /// Location of the original memory access.
+    pub access_ptr: Pointer,
+    /// Size of the original memory access.
+    pub access_size: Size,
+    /// Location of the first uninitialized byte that was accessed.
+    pub uninit_ptr: Pointer,
+    /// Number of consecutive uninitialized bytes that were accessed.
+    pub uninit_size: Size,
+}
+
 /// Error information for when the program caused Undefined Behavior.
 pub enum UndefinedBehaviorInfo<'tcx> {
     /// Free-form case. Only for errors that are never caught!
@@ -384,7 +397,7 @@
     /// Using a string that is not valid UTF-8,
     InvalidStr(std::str::Utf8Error),
     /// Using uninitialized data where it is not allowed.
-    InvalidUninitBytes(Option<Pointer>),
+    InvalidUninitBytes(Option<Box<UninitBytesAccess>>),
     /// Working with a local that is not currently live.
     DeadLocal,
     /// Data size is not equal to target size.
@@ -455,10 +468,18 @@
                 write!(f, "using {} as function pointer but it does not point to a function", p)
             }
             InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err),
-            InvalidUninitBytes(Some(p)) => write!(
+            InvalidUninitBytes(Some(access)) => write!(
                 f,
-                "reading uninitialized memory at {}, but this operation requires initialized memory",
-                p
+                "reading {} byte{} of memory starting at {}, \
+                 but {} byte{} {} uninitialized starting at {}, \
+                 and this operation requires initialized memory",
+                access.access_size.bytes(),
+                pluralize!(access.access_size.bytes()),
+                access.access_ptr,
+                access.uninit_size.bytes(),
+                pluralize!(access.uninit_size.bytes()),
+                if access.uninit_size.bytes() != 1 { "are" } else { "is" },
+                access.uninit_ptr,
             ),
             InvalidUninitBytes(None) => write!(
                 f,
@@ -556,6 +577,9 @@
     }
 }
 
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(InterpError<'_>, 40);
+
 pub enum InterpError<'tcx> {
     /// The program caused undefined behavior.
     UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
@@ -604,7 +628,10 @@
             InterpError::MachineStop(b) => mem::size_of_val::<dyn MachineStopType>(&**b) > 0,
             InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
             | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_))
-            | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
+            | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
+            | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(_))) => {
+                true
+            }
             _ => false,
         }
     }
diff --git a/src/librustc_middle/mir/interpret/mod.rs b/src/librustc_middle/mir/interpret/mod.rs
index 71adb2f..d9e52af 100644
--- a/src/librustc_middle/mir/interpret/mod.rs
+++ b/src/librustc_middle/mir/interpret/mod.rs
@@ -119,7 +119,7 @@
 pub use self::error::{
     struct_error, CheckInAllocMsg, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled,
     FrameInfo, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
-    ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo,
+    ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
 };
 
 pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit};
diff --git a/src/librustc_middle/mir/predecessors.rs b/src/librustc_middle/mir/predecessors.rs
index 9508365..7508c02 100644
--- a/src/librustc_middle/mir/predecessors.rs
+++ b/src/librustc_middle/mir/predecessors.rs
@@ -1,7 +1,7 @@
 //! Lazily compute the reverse control-flow graph for the MIR.
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::{Lock, Lrc};
+use rustc_data_structures::sync::OnceCell;
 use rustc_index::vec::IndexVec;
 use rustc_serialize as serialize;
 use smallvec::SmallVec;
@@ -13,37 +13,33 @@
 
 #[derive(Clone, Debug)]
 pub(super) struct PredecessorCache {
-    cache: Lock<Option<Lrc<Predecessors>>>,
+    cache: OnceCell<Predecessors>,
 }
 
 impl PredecessorCache {
     #[inline]
     pub(super) fn new() -> Self {
-        PredecessorCache { cache: Lock::new(None) }
+        PredecessorCache { cache: OnceCell::new() }
     }
 
     /// Invalidates the predecessor cache.
-    ///
-    /// Invalidating the predecessor cache requires mutating the MIR, which in turn requires a
-    /// unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
-    /// callers of `invalidate` have a unique reference to the MIR and thus to the predecessor
-    /// cache. This means we don't actually need to take a lock when `invalidate` is called.
     #[inline]
     pub(super) fn invalidate(&mut self) {
-        *self.cache.get_mut() = None;
+        // Invalidating the predecessor cache requires mutating the MIR, which in turn requires a
+        // unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
+        // callers of `invalidate` have a unique reference to the MIR and thus to the predecessor
+        // cache. This means we never need to do synchronization when `invalidate` is called, we can
+        // simply reinitialize the `OnceCell`.
+        self.cache = OnceCell::new();
     }
 
-    /// Returns a ref-counted smart pointer containing the predecessor graph for this MIR.
-    ///
-    /// We use ref-counting instead of a mapped `LockGuard` here to ensure that the lock for
-    /// `cache` is only held inside this function. As long as no other locks are taken while
-    /// computing the predecessor graph, deadlock is impossible.
+    /// Returns the the predecessor graph for this MIR.
     #[inline]
     pub(super) fn compute(
         &self,
         basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
-    ) -> Lrc<Predecessors> {
-        Lrc::clone(self.cache.lock().get_or_insert_with(|| {
+    ) -> &Predecessors {
+        self.cache.get_or_init(|| {
             let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks);
             for (bb, data) in basic_blocks.iter_enumerated() {
                 if let Some(term) = &data.terminator {
@@ -53,8 +49,8 @@
                 }
             }
 
-            Lrc::new(preds)
-        }))
+            preds
+        })
     }
 }
 
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index 13cf9a9..f7f5c5d 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -131,7 +131,7 @@
             cache_on_disk_if { key.is_local() }
         }
 
-        query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLibrary>> {
+        query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
             desc { "looking up the native libraries of a linked crate" }
         }
 
@@ -937,7 +937,7 @@
         query is_dllimport_foreign_item(_: DefId) -> bool {}
         query is_statically_included_foreign_item(_: DefId) -> bool {}
         query native_library_kind(_: DefId)
-            -> Option<NativeLibraryKind> {}
+            -> Option<NativeLibKind> {}
     }
 
     Linking {
diff --git a/src/librustc_middle/ty/codec.rs b/src/librustc_middle/ty/codec.rs
index 1cd4af4..c4d5bd7 100644
--- a/src/librustc_middle/ty/codec.rs
+++ b/src/librustc_middle/ty/codec.rs
@@ -10,7 +10,7 @@
 use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use crate::mir::{self, interpret::Allocation};
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, List, Ty, TyCtxt};
+use crate::ty::{self, List, ToPredicate, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
@@ -200,15 +200,16 @@
         (0..decoder.read_usize()?)
             .map(|_| {
                 // Handle shorthands first, if we have an usize > 0x80.
-                let predicate = if decoder.positioned_at_shorthand() {
+                let predicate_kind = if decoder.positioned_at_shorthand() {
                     let pos = decoder.read_usize()?;
                     assert!(pos >= SHORTHAND_OFFSET);
                     let shorthand = pos - SHORTHAND_OFFSET;
 
-                    decoder.with_position(shorthand, ty::Predicate::decode)
+                    decoder.with_position(shorthand, ty::PredicateKind::decode)
                 } else {
-                    ty::Predicate::decode(decoder)
+                    ty::PredicateKind::decode(decoder)
                 }?;
+                let predicate = predicate_kind.to_predicate(tcx);
                 Ok((predicate, Decodable::decode(decoder)?))
             })
             .collect::<Result<Vec<_>, _>>()?,
diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index d2e53fa..68c31c6 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -29,8 +29,9 @@
 use crate::ty::{AdtDef, AdtKind, Const, Region};
 use crate::ty::{BindingMode, BoundVar};
 use crate::ty::{ConstVid, FloatVar, FloatVid, IntVar, IntVid, TyVar, TyVid};
-use crate::ty::{ExistentialPredicate, InferTy, ParamTy, PolyFnSig, Predicate, ProjectionTy};
+use crate::ty::{ExistentialPredicate, Predicate, PredicateKind};
 use crate::ty::{InferConst, ParamConst};
+use crate::ty::{InferTy, ParamTy, PolyFnSig, ProjectionTy};
 use crate::ty::{List, TyKind, TyS};
 use rustc_ast::ast;
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -89,6 +90,7 @@
     canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo>>,
     region: InternedSet<'tcx, RegionKind>,
     existential_predicates: InternedSet<'tcx, List<ExistentialPredicate<'tcx>>>,
+    predicate_kind: InternedSet<'tcx, PredicateKind<'tcx>>,
     predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
@@ -107,6 +109,7 @@
             region: Default::default(),
             existential_predicates: Default::default(),
             canonical_var_infos: Default::default(),
+            predicate_kind: Default::default(),
             predicates: Default::default(),
             projs: Default::default(),
             place_elems: Default::default(),
@@ -1377,7 +1380,7 @@
     pub fn local_crate_exports_generics(self) -> bool {
         debug_assert!(self.sess.opts.share_generics());
 
-        self.sess.crate_types.borrow().iter().any(|crate_type| {
+        self.sess.crate_types().iter().any(|crate_type| {
             match crate_type {
                 CrateType::Executable
                 | CrateType::Staticlib
@@ -1574,6 +1577,7 @@
 nop_lift! {type_; Ty<'a> => Ty<'tcx>}
 nop_lift! {region; Region<'a> => Region<'tcx>}
 nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
+nop_lift! {predicate_kind; &'a PredicateKind<'a> => &'tcx PredicateKind<'tcx>}
 
 nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
 nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>}
@@ -2012,8 +2016,14 @@
     }
 }
 
+impl<'tcx> Borrow<PredicateKind<'tcx>> for Interned<'tcx, PredicateKind<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> {
+        &self.0
+    }
+}
+
 macro_rules! direct_interners {
-    ($($name:ident: $method:ident($ty:ty)),+) => {
+    ($($name:ident: $method:ident($ty:ty),)+) => {
         $(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
             fn eq(&self, other: &Self) -> bool {
                 self.0 == other.0
@@ -2038,7 +2048,11 @@
     }
 }
 
-direct_interners!(region: mk_region(RegionKind), const_: mk_const(Const<'tcx>));
+direct_interners!(
+    region: mk_region(RegionKind),
+    const_: mk_const(Const<'tcx>),
+    predicate_kind: intern_predicate_kind(PredicateKind<'tcx>),
+);
 
 macro_rules! slice_interners {
     ($($field:ident: $method:ident($ty:ty)),+) => (
@@ -2100,6 +2114,12 @@
         self.interners.intern_ty(st)
     }
 
+    #[inline]
+    pub fn mk_predicate(&self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> {
+        let kind = self.intern_predicate_kind(kind);
+        Predicate { kind }
+    }
+
     pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
         match tm {
             ast::IntTy::Isize => self.types.isize,
diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs
index cf63a65..480420d 100644
--- a/src/librustc_middle/ty/error.rs
+++ b/src/librustc_middle/ty/error.rs
@@ -815,19 +815,18 @@
                 for item in &items[..] {
                     match item.kind {
                         hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => {
-                            if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
-                                if let hir::Defaultness::Default { has_value: true } =
-                                    item.defaultness
-                                {
+                            // FIXME: account for returning some type in a trait fn impl that has
+                            // an assoc type as a return type (#72076).
+                            if let hir::Defaultness::Default { has_value: true } = item.defaultness
+                            {
+                                if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
                                     db.span_label(
                                         item.span,
                                         "associated type defaults can't be assumed inside the \
                                             trait defining them",
                                     );
-                                } else {
-                                    db.span_label(item.span, "expected this associated type");
+                                    return true;
                                 }
-                                return true;
                             }
                         }
                         _ => {}
diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs
index 2d49d85..5566e18 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -187,7 +187,7 @@
     query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
 ) -> Result<&'tcx Layout, LayoutError<'tcx>> {
     ty::tls::with_related_context(tcx, move |icx| {
-        let rec_limit = *tcx.sess.recursion_limit.get();
+        let rec_limit = tcx.sess.recursion_limit.get().copied().unwrap();
         let (param_env, ty) = query.into_parts();
 
         if icx.layout_depth > rec_limit {
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 36bc44f..9e84566 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -1016,9 +1016,30 @@
     }
 }
 
+#[derive(Clone, Copy, Hash, RustcEncodable, RustcDecodable, Lift)]
+#[derive(HashStable)]
+pub struct Predicate<'tcx> {
+    kind: &'tcx PredicateKind<'tcx>,
+}
+
+impl<'tcx> PartialEq for Predicate<'tcx> {
+    fn eq(&self, other: &Self) -> bool {
+        // `self.kind` is always interned.
+        ptr::eq(self.kind, other.kind)
+    }
+}
+
+impl<'tcx> Eq for Predicate<'tcx> {}
+
+impl<'tcx> Predicate<'tcx> {
+    pub fn kind(self) -> &'tcx PredicateKind<'tcx> {
+        self.kind
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 #[derive(HashStable, TypeFoldable)]
-pub enum Predicate<'tcx> {
+pub enum PredicateKind<'tcx> {
     /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
     /// would be the type parameters.
@@ -1086,7 +1107,7 @@
     /// substitution in terms of what happens with bound regions. See
     /// lengthy comment below for details.
     pub fn subst_supertrait(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         trait_ref: &ty::PolyTraitRef<'tcx>,
     ) -> ty::Predicate<'tcx> {
@@ -1151,34 +1172,36 @@
         // this trick achieves that).
 
         let substs = &trait_ref.skip_binder().substs;
-        match *self {
-            Predicate::Trait(ref binder, constness) => {
-                Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness)
+        let predicate = match self.kind() {
+            &PredicateKind::Trait(ref binder, constness) => {
+                PredicateKind::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness)
             }
-            Predicate::Subtype(ref binder) => {
-                Predicate::Subtype(binder.map_bound(|data| data.subst(tcx, substs)))
+            PredicateKind::Subtype(binder) => {
+                PredicateKind::Subtype(binder.map_bound(|data| data.subst(tcx, substs)))
             }
-            Predicate::RegionOutlives(ref binder) => {
-                Predicate::RegionOutlives(binder.map_bound(|data| data.subst(tcx, substs)))
+            PredicateKind::RegionOutlives(binder) => {
+                PredicateKind::RegionOutlives(binder.map_bound(|data| data.subst(tcx, substs)))
             }
-            Predicate::TypeOutlives(ref binder) => {
-                Predicate::TypeOutlives(binder.map_bound(|data| data.subst(tcx, substs)))
+            PredicateKind::TypeOutlives(binder) => {
+                PredicateKind::TypeOutlives(binder.map_bound(|data| data.subst(tcx, substs)))
             }
-            Predicate::Projection(ref binder) => {
-                Predicate::Projection(binder.map_bound(|data| data.subst(tcx, substs)))
+            PredicateKind::Projection(binder) => {
+                PredicateKind::Projection(binder.map_bound(|data| data.subst(tcx, substs)))
             }
-            Predicate::WellFormed(data) => Predicate::WellFormed(data.subst(tcx, substs)),
-            Predicate::ObjectSafe(trait_def_id) => Predicate::ObjectSafe(trait_def_id),
-            Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
-                Predicate::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind)
+            &PredicateKind::WellFormed(data) => PredicateKind::WellFormed(data.subst(tcx, substs)),
+            &PredicateKind::ObjectSafe(trait_def_id) => PredicateKind::ObjectSafe(trait_def_id),
+            &PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
+                PredicateKind::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind)
             }
-            Predicate::ConstEvaluatable(def_id, const_substs) => {
-                Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs))
+            &PredicateKind::ConstEvaluatable(def_id, const_substs) => {
+                PredicateKind::ConstEvaluatable(def_id, const_substs.subst(tcx, substs))
             }
-            Predicate::ConstEquate(c1, c2) => {
-                Predicate::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs))
+            PredicateKind::ConstEquate(c1, c2) => {
+                PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs))
             }
-        }
+        };
+
+        predicate.to_predicate(tcx)
     }
 }
 
@@ -1293,85 +1316,95 @@
 }
 
 pub trait ToPredicate<'tcx> {
-    fn to_predicate(&self) -> Predicate<'tcx>;
+    fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>;
+}
+
+impl ToPredicate<'tcx> for PredicateKind<'tcx> {
+    fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        tcx.mk_predicate(*self)
+    }
 }
 
 impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
-    fn to_predicate(&self) -> Predicate<'tcx> {
-        ty::Predicate::Trait(
+    fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        ty::PredicateKind::Trait(
             ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value }),
             self.constness,
         )
+        .to_predicate(tcx)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> {
-    fn to_predicate(&self) -> Predicate<'tcx> {
-        ty::Predicate::Trait(
+    fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        ty::PredicateKind::Trait(
             ty::Binder::dummy(ty::TraitPredicate { trait_ref: *self.value }),
             self.constness,
         )
+        .to_predicate(tcx)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
-    fn to_predicate(&self) -> Predicate<'tcx> {
-        ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness)
+    fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness)
+            .to_predicate(tcx)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> {
-    fn to_predicate(&self) -> Predicate<'tcx> {
-        ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness)
+    fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness)
+            .to_predicate(tcx)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
-    fn to_predicate(&self) -> Predicate<'tcx> {
-        Predicate::RegionOutlives(*self)
+    fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        PredicateKind::RegionOutlives(*self).to_predicate(tcx)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
-    fn to_predicate(&self) -> Predicate<'tcx> {
-        Predicate::TypeOutlives(*self)
+    fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        PredicateKind::TypeOutlives(*self).to_predicate(tcx)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
-    fn to_predicate(&self) -> Predicate<'tcx> {
-        Predicate::Projection(*self)
+    fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        PredicateKind::Projection(*self).to_predicate(tcx)
     }
 }
 
 impl<'tcx> Predicate<'tcx> {
-    pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> {
-        match *self {
-            Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()),
-            Predicate::Projection(..)
-            | Predicate::Subtype(..)
-            | Predicate::RegionOutlives(..)
-            | Predicate::WellFormed(..)
-            | Predicate::ObjectSafe(..)
-            | Predicate::ClosureKind(..)
-            | Predicate::TypeOutlives(..)
-            | Predicate::ConstEvaluatable(..)
-            | Predicate::ConstEquate(..) => None,
+    pub fn to_opt_poly_trait_ref(self) -> Option<PolyTraitRef<'tcx>> {
+        match self.kind() {
+            &PredicateKind::Trait(ref t, _) => Some(t.to_poly_trait_ref()),
+            PredicateKind::Projection(..)
+            | PredicateKind::Subtype(..)
+            | PredicateKind::RegionOutlives(..)
+            | PredicateKind::WellFormed(..)
+            | PredicateKind::ObjectSafe(..)
+            | PredicateKind::ClosureKind(..)
+            | PredicateKind::TypeOutlives(..)
+            | PredicateKind::ConstEvaluatable(..)
+            | PredicateKind::ConstEquate(..) => None,
         }
     }
 
-    pub fn to_opt_type_outlives(&self) -> Option<PolyTypeOutlivesPredicate<'tcx>> {
-        match *self {
-            Predicate::TypeOutlives(data) => Some(data),
-            Predicate::Trait(..)
-            | Predicate::Projection(..)
-            | Predicate::Subtype(..)
-            | Predicate::RegionOutlives(..)
-            | Predicate::WellFormed(..)
-            | Predicate::ObjectSafe(..)
-            | Predicate::ClosureKind(..)
-            | Predicate::ConstEvaluatable(..)
-            | Predicate::ConstEquate(..) => None,
+    pub fn to_opt_type_outlives(self) -> Option<PolyTypeOutlivesPredicate<'tcx>> {
+        match self.kind() {
+            &PredicateKind::TypeOutlives(data) => Some(data),
+            PredicateKind::Trait(..)
+            | PredicateKind::Projection(..)
+            | PredicateKind::Subtype(..)
+            | PredicateKind::RegionOutlives(..)
+            | PredicateKind::WellFormed(..)
+            | PredicateKind::ObjectSafe(..)
+            | PredicateKind::ClosureKind(..)
+            | PredicateKind::ConstEvaluatable(..)
+            | PredicateKind::ConstEquate(..) => None,
         }
     }
 }
@@ -1617,7 +1650,7 @@
     pub value: T,
 }
 
-// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate()` to ensure that
+// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that
 // the constness of trait bounds is being propagated correctly.
 pub trait WithConstness: Sized {
     #[inline]
diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs
index 2502a4a..f03d91a 100644
--- a/src/librustc_middle/ty/print/pretty.rs
+++ b/src/librustc_middle/ty/print/pretty.rs
@@ -1,5 +1,4 @@
 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
-use crate::middle::region;
 use crate::mir::interpret::{sign_extend, truncate, AllocId, ConstValue, Pointer, Scalar};
 use crate::ty::layout::IntegerExt;
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
@@ -1588,9 +1587,9 @@
                 false
             }
 
-            ty::ReScope(_) | ty::ReVar(_) if identify_regions => true,
+            ty::ReVar(_) if identify_regions => true,
 
-            ty::ReVar(_) | ty::ReScope(_) | ty::ReErased => false,
+            ty::ReVar(_) | ty::ReErased => false,
 
             ty::ReStatic | ty::ReEmpty(_) => true,
         }
@@ -1666,32 +1665,12 @@
                     }
                 }
             }
-            ty::ReScope(scope) if identify_regions => {
-                match scope.data {
-                    region::ScopeData::Node => p!(write("'{}s", scope.item_local_id().as_usize())),
-                    region::ScopeData::CallSite => {
-                        p!(write("'{}cs", scope.item_local_id().as_usize()))
-                    }
-                    region::ScopeData::Arguments => {
-                        p!(write("'{}as", scope.item_local_id().as_usize()))
-                    }
-                    region::ScopeData::Destruction => {
-                        p!(write("'{}ds", scope.item_local_id().as_usize()))
-                    }
-                    region::ScopeData::Remainder(first_statement_index) => p!(write(
-                        "'{}_{}rs",
-                        scope.item_local_id().as_usize(),
-                        first_statement_index.index()
-                    )),
-                }
-                return Ok(self);
-            }
             ty::ReVar(region_vid) if identify_regions => {
                 p!(write("{:?}", region_vid));
                 return Ok(self);
             }
             ty::ReVar(_) => {}
-            ty::ReScope(_) | ty::ReErased => {}
+            ty::ReErased => {}
             ty::ReStatic => {
                 p!(write("'static"));
                 return Ok(self);
@@ -2031,34 +2010,34 @@
     }
 
     ty::Predicate<'tcx> {
-        match *self {
-            ty::Predicate::Trait(ref data, constness) => {
+        match self.kind() {
+            &ty::PredicateKind::Trait(ref data, constness) => {
                 if let hir::Constness::Const = constness {
                     p!(write("const "));
                 }
                 p!(print(data))
             }
-            ty::Predicate::Subtype(ref predicate) => p!(print(predicate)),
-            ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)),
-            ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)),
-            ty::Predicate::Projection(ref predicate) => p!(print(predicate)),
-            ty::Predicate::WellFormed(ty) => p!(print(ty), write(" well-formed")),
-            ty::Predicate::ObjectSafe(trait_def_id) => {
+            ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
+            ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)),
+            ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)),
+            ty::PredicateKind::Projection(predicate) => p!(print(predicate)),
+            ty::PredicateKind::WellFormed(ty) => p!(print(ty), write(" well-formed")),
+            &ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 p!(write("the trait `"),
                    print_def_path(trait_def_id, &[]),
                    write("` is object-safe"))
             }
-            ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => {
+            &ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => {
                 p!(write("the closure `"),
                    print_value_path(closure_def_id, &[]),
                    write("` implements the trait `{}`", kind))
             }
-            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+            &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
                 p!(write("the constant `"),
                    print_value_path(def_id, substs),
                    write("` can be evaluated"))
             }
-            ty::Predicate::ConstEquate(c1, c2) => {
+            ty::PredicateKind::ConstEquate(c1, c2) => {
                 p!(write("the constant `"),
                    print(c1),
                    write("` equals `"),
diff --git a/src/librustc_middle/ty/query/mod.rs b/src/librustc_middle/ty/query/mod.rs
index e1a5a76..f61fc65 100644
--- a/src/librustc_middle/ty/query/mod.rs
+++ b/src/librustc_middle/ty/query/mod.rs
@@ -4,8 +4,8 @@
 use crate::infer::canonical::{self, Canonical};
 use crate::lint::LintLevelMap;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
-use crate::middle::cstore::{CrateSource, DepKind, NativeLibraryKind};
-use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLibrary};
+use crate::middle::cstore::{CrateSource, DepKind};
+use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
 use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use crate::middle::lib_features::LibFeatures;
 use crate::middle::privacy::AccessLevels;
@@ -46,6 +46,7 @@
 use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate};
 use rustc_index::vec::IndexVec;
 use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
+use rustc_session::utils::NativeLibKind;
 use rustc_session::CrateDisambiguator;
 use rustc_target::spec::PanicStrategy;
 
diff --git a/src/librustc_middle/ty/query/on_disk_cache.rs b/src/librustc_middle/ty/query/on_disk_cache.rs
index 71c2c24..4eae067 100644
--- a/src/librustc_middle/ty/query/on_disk_cache.rs
+++ b/src/librustc_middle/ty/query/on_disk_cache.rs
@@ -6,7 +6,7 @@
 use crate::ty::{self, Ty};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, Once};
+use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
@@ -49,7 +49,7 @@
     current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
 
     prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
-    cnum_map: Once<IndexVec<CrateNum, Option<CrateNum>>>,
+    cnum_map: OnceCell<IndexVec<CrateNum, Option<CrateNum>>>,
 
     source_map: &'sess SourceMap,
     file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
@@ -128,7 +128,7 @@
             file_index_to_stable_id: footer.file_index_to_stable_id,
             file_index_to_file: Default::default(),
             prev_cnums: footer.prev_cnums,
-            cnum_map: Once::new(),
+            cnum_map: OnceCell::new(),
             source_map: sess.source_map(),
             current_diagnostics: Default::default(),
             query_result_index: footer.query_result_index.into_iter().collect(),
@@ -144,7 +144,7 @@
             file_index_to_stable_id: Default::default(),
             file_index_to_file: Default::default(),
             prev_cnums: vec![],
-            cnum_map: Once::new(),
+            cnum_map: OnceCell::new(),
             source_map,
             current_diagnostics: Default::default(),
             query_result_index: Default::default(),
@@ -370,14 +370,14 @@
     {
         let pos = index.get(&dep_node_index).cloned()?;
 
-        // Initialize `cnum_map` using the value from the thread that finishes the closure first.
-        self.cnum_map.init_nonlocking_same(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
+        let cnum_map =
+            self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
 
         let mut decoder = CacheDecoder {
             tcx,
             opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()),
             source_map: self.source_map,
-            cnum_map: self.cnum_map.get(),
+            cnum_map,
             synthetic_syntax_contexts: &self.synthetic_syntax_contexts,
             file_index_to_file: &self.file_index_to_file,
             file_index_to_stable_id: &self.file_index_to_stable_id,
diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs
index c23a351..569a8d9 100644
--- a/src/librustc_middle/ty/structural_impls.rs
+++ b/src/librustc_middle/ty/structural_impls.rs
@@ -87,8 +87,6 @@
 
             ty::ReFree(ref fr) => fr.fmt(f),
 
-            ty::ReScope(id) => write!(f, "ReScope({:?})", id),
-
             ty::ReStatic => write!(f, "ReStatic"),
 
             ty::ReVar(ref vid) => vid.fmt(f),
@@ -221,26 +219,34 @@
 
 impl fmt::Debug for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self.kind())
+    }
+}
+
+impl fmt::Debug for ty::PredicateKind<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            ty::Predicate::Trait(ref a, constness) => {
+            ty::PredicateKind::Trait(ref a, constness) => {
                 if let hir::Constness::Const = constness {
                     write!(f, "const ")?;
                 }
                 a.fmt(f)
             }
-            ty::Predicate::Subtype(ref pair) => pair.fmt(f),
-            ty::Predicate::RegionOutlives(ref pair) => pair.fmt(f),
-            ty::Predicate::TypeOutlives(ref pair) => pair.fmt(f),
-            ty::Predicate::Projection(ref pair) => pair.fmt(f),
-            ty::Predicate::WellFormed(ty) => write!(f, "WellFormed({:?})", ty),
-            ty::Predicate::ObjectSafe(trait_def_id) => write!(f, "ObjectSafe({:?})", trait_def_id),
-            ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
+            ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
+            ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f),
+            ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f),
+            ty::PredicateKind::Projection(ref pair) => pair.fmt(f),
+            ty::PredicateKind::WellFormed(ty) => write!(f, "WellFormed({:?})", ty),
+            ty::PredicateKind::ObjectSafe(trait_def_id) => {
+                write!(f, "ObjectSafe({:?})", trait_def_id)
+            }
+            ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                 write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
             }
-            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+            ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
                 write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
             }
-            ty::Predicate::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
+            ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
         }
     }
 }
@@ -467,37 +473,39 @@
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
-    type Lifted = ty::Predicate<'tcx>;
+impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
+    type Lifted = ty::PredicateKind<'tcx>;
     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         match *self {
-            ty::Predicate::Trait(ref binder, constness) => {
-                tcx.lift(binder).map(|binder| ty::Predicate::Trait(binder, constness))
+            ty::PredicateKind::Trait(ref binder, constness) => {
+                tcx.lift(binder).map(|binder| ty::PredicateKind::Trait(binder, constness))
             }
-            ty::Predicate::Subtype(ref binder) => tcx.lift(binder).map(ty::Predicate::Subtype),
-            ty::Predicate::RegionOutlives(ref binder) => {
-                tcx.lift(binder).map(ty::Predicate::RegionOutlives)
+            ty::PredicateKind::Subtype(ref binder) => {
+                tcx.lift(binder).map(ty::PredicateKind::Subtype)
             }
-            ty::Predicate::TypeOutlives(ref binder) => {
-                tcx.lift(binder).map(ty::Predicate::TypeOutlives)
+            ty::PredicateKind::RegionOutlives(ref binder) => {
+                tcx.lift(binder).map(ty::PredicateKind::RegionOutlives)
             }
-            ty::Predicate::Projection(ref binder) => {
-                tcx.lift(binder).map(ty::Predicate::Projection)
+            ty::PredicateKind::TypeOutlives(ref binder) => {
+                tcx.lift(binder).map(ty::PredicateKind::TypeOutlives)
             }
-            ty::Predicate::WellFormed(ty) => tcx.lift(&ty).map(ty::Predicate::WellFormed),
-            ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
+            ty::PredicateKind::Projection(ref binder) => {
+                tcx.lift(binder).map(ty::PredicateKind::Projection)
+            }
+            ty::PredicateKind::WellFormed(ty) => tcx.lift(&ty).map(ty::PredicateKind::WellFormed),
+            ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                 tcx.lift(&closure_substs).map(|closure_substs| {
-                    ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind)
+                    ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind)
                 })
             }
-            ty::Predicate::ObjectSafe(trait_def_id) => {
-                Some(ty::Predicate::ObjectSafe(trait_def_id))
+            ty::PredicateKind::ObjectSafe(trait_def_id) => {
+                Some(ty::PredicateKind::ObjectSafe(trait_def_id))
             }
-            ty::Predicate::ConstEvaluatable(def_id, substs) => {
-                tcx.lift(&substs).map(|substs| ty::Predicate::ConstEvaluatable(def_id, substs))
+            ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
+                tcx.lift(&substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs))
             }
-            ty::Predicate::ConstEquate(c1, c2) => {
-                tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::Predicate::ConstEquate(c1, c2))
+            ty::PredicateKind::ConstEquate(c1, c2) => {
+                tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2))
             }
         }
     }
@@ -977,6 +985,16 @@
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        folder.tcx().mk_predicate(ty::PredicateKind::super_fold_with(self.kind, folder))
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        ty::PredicateKind::super_visit_with(self.kind, visitor)
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v))
diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs
index 2ad673b..370702f 100644
--- a/src/librustc_middle/ty/sty.rs
+++ b/src/librustc_middle/ty/sty.rs
@@ -6,7 +6,6 @@
 use self::TyKind::*;
 
 use crate::infer::canonical::Canonical;
-use crate::middle::region;
 use crate::mir::interpret::ConstValue;
 use crate::mir::interpret::{LitToConstInput, Scalar};
 use crate::mir::Promoted;
@@ -612,15 +611,16 @@
         use crate::ty::ToPredicate;
         match *self.skip_binder() {
             ExistentialPredicate::Trait(tr) => {
-                Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate()
+                Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx)
             }
             ExistentialPredicate::Projection(p) => {
-                ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty)))
+                ty::PredicateKind::Projection(Binder(p.with_self_ty(tcx, self_ty)))
+                    .to_predicate(tcx)
             }
             ExistentialPredicate::AutoTrait(did) => {
                 let trait_ref =
                     Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) });
-                trait_ref.without_const().to_predicate()
+                trait_ref.without_const().to_predicate(tcx)
             }
         }
     }
@@ -1178,17 +1178,15 @@
 
 pub type Region<'tcx> = &'tcx RegionKind;
 
-/// Representation of (lexical) regions. Note that the NLL checker
-/// uses a distinct representation of regions. For this reason, it
-/// internally replaces all the regions with inference variables --
-/// the index of the variable is then used to index into internal NLL
-/// data structures. See `rustc_mir::borrow_check` module for more
-/// information.
+/// Representation of regions. Note that the NLL checker uses a distinct
+/// representation of regions. For this reason, it internally replaces all the
+/// regions with inference variables -- the index of the variable is then used
+/// to index into internal NLL data structures. See `rustc_mir::borrow_check`
+/// module for more information.
 ///
 /// ## The Region lattice within a given function
 ///
-/// In general, the (lexical, and hence deprecated) region lattice
-/// looks like
+/// In general, the region lattice looks like
 ///
 /// ```
 /// static ----------+-----...------+       (greatest)
@@ -1196,7 +1194,6 @@
 /// early-bound and  |              |
 /// free regions     |              |
 /// |                |              |
-/// scope regions    |              |
 /// |                |              |
 /// empty(root)   placeholder(U1)   |
 /// |            /                  |
@@ -1211,13 +1208,7 @@
 /// Early-bound/free regions are the named lifetimes in scope from the
 /// function declaration. They have relationships to one another
 /// determined based on the declared relationships from the
-/// function. They all collectively outlive the scope regions. (See
-/// `RegionRelations` type, and particularly
-/// `crate::infer::outlives::free_region_map::FreeRegionMap`.)
-///
-/// The scope regions are related to one another based on the AST
-/// structure. (See `RegionRelations` type, and particularly the
-/// `rustc_middle::middle::region::ScopeTree`.)
+/// function.
 ///
 /// Note that inference variables and bound regions are not included
 /// in this diagram. In the case of inference variables, they should
@@ -1306,11 +1297,6 @@
     /// region parameters.
     ReFree(FreeRegion),
 
-    /// A concrete region naming some statically determined scope
-    /// (e.g., an expression or sequence of statements) within the
-    /// current function.
-    ReScope(region::Scope),
-
     /// Static data that has an "infinite" lifetime. Top in the region lattice.
     ReStatic,
 
@@ -1534,7 +1520,6 @@
             RegionKind::ReEarlyBound(ebr) => ebr.has_name(),
             RegionKind::ReLateBound(_, br) => br.is_named(),
             RegionKind::ReFree(fr) => fr.bound_region.is_named(),
-            RegionKind::ReScope(..) => false,
             RegionKind::ReStatic => true,
             RegionKind::ReVar(..) => false,
             RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(),
@@ -1615,7 +1600,7 @@
                 flags = flags | TypeFlags::HAS_RE_PARAM;
                 flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
             }
-            ty::ReFree { .. } | ty::ReScope { .. } => {
+            ty::ReFree { .. } => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
             }
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
index 98c0542..e19fab8 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -162,10 +162,8 @@
                     let type_test_span = type_test.locations.span(&self.body);
 
                     if let Some(lower_bound_region) = lower_bound_region {
-                        let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
                         self.infcx
                             .construct_generic_bound_failure(
-                                region_scope_tree,
                                 type_test_span,
                                 None,
                                 type_test.generic_kind,
@@ -194,12 +192,10 @@
                 }
 
                 RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => {
-                    let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
                     let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
                     let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
                     unexpected_hidden_region_diagnostic(
                         self.infcx.tcx,
-                        Some(region_scope_tree),
                         span,
                         named_ty,
                         named_region,
@@ -576,7 +572,7 @@
 
                     let mut found = false;
                     for predicate in bounds.predicates {
-                        if let ty::Predicate::TypeOutlives(binder) = predicate {
+                        if let ty::PredicateKind::TypeOutlives(binder) = predicate.kind() {
                             if let ty::OutlivesPredicate(_, ty::RegionKind::ReStatic) =
                                 binder.skip_binder()
                             {
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
index 37e2e04..e912ef7 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
@@ -284,7 +284,6 @@
             },
 
             ty::ReLateBound(..)
-            | ty::ReScope(..)
             | ty::ReVar(..)
             | ty::RePlaceholder(..)
             | ty::ReEmpty(_)
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 08aa434..bdbce1d 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -27,8 +27,8 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts};
 use rustc_middle::ty::{
-    self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPolyTraitRef, Ty,
-    TyCtxt, UserType, UserTypeAnnotationIndex,
+    self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPolyTraitRef,
+    ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
 };
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
@@ -1016,7 +1016,7 @@
                     }
 
                     self.prove_predicate(
-                        ty::Predicate::WellFormed(inferred_ty),
+                        ty::PredicateKind::WellFormed(inferred_ty).to_predicate(self.tcx()),
                         Locations::All(span),
                         ConstraintCategory::TypeAnnotation,
                     );
@@ -1268,7 +1268,7 @@
                     obligations.obligations.push(traits::Obligation::new(
                         ObligationCause::dummy(),
                         param_env,
-                        ty::Predicate::WellFormed(revealed_ty),
+                        ty::PredicateKind::WellFormed(revealed_ty).to_predicate(infcx.tcx),
                     ));
                     obligations.add(
                         infcx
@@ -1612,7 +1612,7 @@
                 self.check_call_dest(body, term, &sig, destination, term_location);
 
                 self.prove_predicates(
-                    sig.inputs_and_output.iter().map(|ty| ty::Predicate::WellFormed(ty)),
+                    sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty)),
                     term_location.to_locations(),
                     ConstraintCategory::Boring,
                 );
@@ -2017,7 +2017,7 @@
                                         traits::ObligationCauseCode::RepeatVec(should_suggest),
                                     ),
                                     self.param_env,
-                                    ty::Predicate::Trait(
+                                    ty::PredicateKind::Trait(
                                         ty::Binder::bind(ty::TraitPredicate {
                                             trait_ref: ty::TraitRef::new(
                                                 self.tcx().require_lang_item(
@@ -2028,7 +2028,8 @@
                                             ),
                                         }),
                                         hir::Constness::NotConst,
-                                    ),
+                                    )
+                                    .to_predicate(self.tcx()),
                                 ),
                                 &traits::SelectionError::Unimplemented,
                                 false,
@@ -2686,7 +2687,7 @@
         category: ConstraintCategory,
     ) {
         self.prove_predicates(
-            Some(ty::Predicate::Trait(
+            Some(ty::PredicateKind::Trait(
                 trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
                 hir::Constness::NotConst,
             )),
@@ -2708,11 +2709,12 @@
 
     fn prove_predicates(
         &mut self,
-        predicates: impl IntoIterator<Item = ty::Predicate<'tcx>>,
+        predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
         locations: Locations,
         category: ConstraintCategory,
     ) {
         for predicate in predicates {
+            let predicate = predicate.to_predicate(self.tcx());
             debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,);
 
             self.prove_predicate(predicate, locations, category);
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index 0637ebf..fd5e063 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -89,7 +89,7 @@
     InterpCx::new(
         tcx.at(span),
         param_env,
-        CompileTimeInterpreter::new(*tcx.sess.const_eval_limit.get()),
+        CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
         MemoryExtra { can_access_statics },
     )
 }
@@ -303,7 +303,7 @@
     let mut ecx = InterpCx::new(
         tcx.at(span),
         key.param_env,
-        CompileTimeInterpreter::new(*tcx.sess.const_eval_limit.get()),
+        CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
         MemoryExtra { can_access_statics: is_static },
     );
 
diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
index f929b2d..b61dc56 100644
--- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs
+++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
@@ -99,6 +99,9 @@
 where
     K: BorrowAnalysisKind<'tcx>,
 {
+    // The generator transform relies on the fact that this analysis does **not** use "before"
+    // effects.
+
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
diff --git a/src/librustc_mir/dataflow/impls/init_locals.rs b/src/librustc_mir/dataflow/impls/init_locals.rs
new file mode 100644
index 0000000..726330b
--- /dev/null
+++ b/src/librustc_mir/dataflow/impls/init_locals.rs
@@ -0,0 +1,118 @@
+//! A less precise version of `MaybeInitializedPlaces` whose domain is entire locals.
+//!
+//! A local will be maybe initialized if *any* projections of that local might be initialized.
+
+use crate::dataflow::{self, BottomValue, GenKill};
+
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::visit::{PlaceContext, Visitor};
+use rustc_middle::mir::{self, BasicBlock, Local, Location};
+
+pub struct MaybeInitializedLocals;
+
+impl BottomValue for MaybeInitializedLocals {
+    /// bottom = uninit
+    const BOTTOM_VALUE: bool = false;
+}
+
+impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals {
+    type Idx = Local;
+
+    const NAME: &'static str = "maybe_init_locals";
+
+    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
+        body.local_decls.len()
+    }
+
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut BitSet<Self::Idx>) {
+        // Function arguments are initialized to begin with.
+        for arg in body.args_iter() {
+            entry_set.insert(arg);
+        }
+    }
+}
+
+impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
+    // The generator transform relies on the fact that this analysis does **not** use "before"
+    // effects.
+
+    fn statement_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        statement: &mir::Statement<'tcx>,
+        loc: Location,
+    ) {
+        TransferFunction { trans }.visit_statement(statement, loc)
+    }
+
+    fn terminator_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        terminator: &mir::Terminator<'tcx>,
+        loc: Location,
+    ) {
+        TransferFunction { trans }.visit_terminator(terminator, loc)
+    }
+
+    fn call_return_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _block: BasicBlock,
+        _func: &mir::Operand<'tcx>,
+        _args: &[mir::Operand<'tcx>],
+        return_place: mir::Place<'tcx>,
+    ) {
+        trans.gen(return_place.local)
+    }
+
+    /// See `Analysis::apply_yield_resume_effect`.
+    fn yield_resume_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _resume_block: BasicBlock,
+        resume_place: mir::Place<'tcx>,
+    ) {
+        trans.gen(resume_place.local)
+    }
+}
+
+struct TransferFunction<'a, T> {
+    trans: &'a mut T,
+}
+
+impl<T> Visitor<'tcx> for TransferFunction<'a, T>
+where
+    T: GenKill<Local>,
+{
+    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
+        use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext};
+        match context {
+            // These are handled specially in `call_return_effect` and `yield_resume_effect`.
+            PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {}
+
+            // Otherwise, when a place is mutated, we must consider it possibly initialized.
+            PlaceContext::MutatingUse(_) => self.trans.gen(local),
+
+            // If the local is moved out of, or if it gets marked `StorageDead`, consider it no
+            // longer initialized.
+            PlaceContext::NonUse(NonUseContext::StorageDead)
+            | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => self.trans.kill(local),
+
+            // All other uses do not affect this analysis.
+            PlaceContext::NonUse(
+                NonUseContext::StorageLive
+                | NonUseContext::AscribeUserTy
+                | NonUseContext::VarDebugInfo,
+            )
+            | PlaceContext::NonMutatingUse(
+                NonMutatingUseContext::Inspect
+                | NonMutatingUseContext::Copy
+                | NonMutatingUseContext::SharedBorrow
+                | NonMutatingUseContext::ShallowBorrow
+                | NonMutatingUseContext::UniqueBorrow
+                | NonMutatingUseContext::AddressOf
+                | NonMutatingUseContext::Projection,
+            ) => {}
+        }
+    }
+}
diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs
index e199a17..ed01d6b 100644
--- a/src/librustc_mir/dataflow/impls/mod.rs
+++ b/src/librustc_mir/dataflow/impls/mod.rs
@@ -22,13 +22,15 @@
 
 mod borrowed_locals;
 pub(super) mod borrows;
+mod init_locals;
 mod liveness;
 mod storage_liveness;
 
 pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
 pub use self::borrows::Borrows;
+pub use self::init_locals::MaybeInitializedLocals;
 pub use self::liveness::MaybeLiveLocals;
-pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
+pub use self::storage_liveness::MaybeStorageLive;
 
 /// `MaybeInitializedPlaces` tracks all places that might be
 /// initialized upon reaching a particular point in the control flow
diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs
index bbc4942..2a2be06 100644
--- a/src/librustc_mir/dataflow/impls/storage_liveness.rs
+++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs
@@ -1,11 +1,9 @@
 pub use super::*;
 
 use crate::dataflow::BottomValue;
-use crate::dataflow::{self, GenKill, Results, ResultsRefCursor};
+use crate::dataflow::{self, GenKill};
 use crate::util::storage::AlwaysLiveLocals;
-use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use std::cell::RefCell;
 
 #[derive(Clone)]
 pub struct MaybeStorageLive {
@@ -78,233 +76,3 @@
     /// bottom = dead
     const BOTTOM_VALUE: bool = false;
 }
-
-type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>;
-
-/// Dataflow analysis that determines whether each local requires storage at a
-/// given location; i.e. whether its storage can go away without being observed.
-pub struct MaybeRequiresStorage<'mir, 'tcx> {
-    body: &'mir Body<'tcx>,
-    borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
-}
-
-impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
-    pub fn new(
-        body: &'mir Body<'tcx>,
-        borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>,
-    ) -> Self {
-        MaybeRequiresStorage {
-            body,
-            borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)),
-        }
-    }
-}
-
-impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
-    type Idx = Local;
-
-    const NAME: &'static str = "requires_storage";
-
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls.len()
-    }
-
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) {
-        // The resume argument is live on function entry (we don't care about
-        // the `self` argument)
-        for arg in body.args_iter().skip(1) {
-            on_entry.insert(arg);
-        }
-    }
-}
-
-impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
-    fn before_statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        stmt: &mir::Statement<'tcx>,
-        loc: Location,
-    ) {
-        // If a place is borrowed in a statement, it needs storage for that statement.
-        self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc);
-
-        match &stmt.kind {
-            StatementKind::StorageDead(l) => trans.kill(*l),
-
-            // If a place is assigned to in a statement, it needs storage for that statement.
-            StatementKind::Assign(box (place, _))
-            | StatementKind::SetDiscriminant { box place, .. } => {
-                trans.gen(place.local);
-            }
-            StatementKind::LlvmInlineAsm(asm) => {
-                for place in &*asm.outputs {
-                    trans.gen(place.local);
-                }
-            }
-
-            // Nothing to do for these. Match exhaustively so this fails to compile when new
-            // variants are added.
-            StatementKind::AscribeUserType(..)
-            | StatementKind::FakeRead(..)
-            | StatementKind::Nop
-            | StatementKind::Retag(..)
-            | StatementKind::StorageLive(..) => {}
-        }
-    }
-
-    fn statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _: &mir::Statement<'tcx>,
-        loc: Location,
-    ) {
-        // If we move from a place then only stops needing storage *after*
-        // that statement.
-        self.check_for_move(trans, loc);
-    }
-
-    fn before_terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        terminator: &mir::Terminator<'tcx>,
-        loc: Location,
-    ) {
-        // If a place is borrowed in a terminator, it needs storage for that terminator.
-        self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc);
-
-        match &terminator.kind {
-            TerminatorKind::Call { destination: Some((place, _)), .. } => {
-                trans.gen(place.local);
-            }
-
-            // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
-            // that is that a `yield` will return from the function, and `resume_arg` is written
-            // only when the generator is later resumed. Unlike `Call`, this doesn't require the
-            // place to have storage *before* the yield, only after.
-            TerminatorKind::Yield { .. } => {}
-
-            TerminatorKind::InlineAsm { operands, .. } => {
-                for op in operands {
-                    match op {
-                        InlineAsmOperand::Out { place, .. }
-                        | InlineAsmOperand::InOut { out_place: place, .. } => {
-                            if let Some(place) = place {
-                                trans.gen(place.local);
-                            }
-                        }
-                        InlineAsmOperand::In { .. }
-                        | InlineAsmOperand::Const { .. }
-                        | InlineAsmOperand::SymFn { .. }
-                        | InlineAsmOperand::SymStatic { .. } => {}
-                    }
-                }
-            }
-
-            // Nothing to do for these. Match exhaustively so this fails to compile when new
-            // variants are added.
-            TerminatorKind::Call { destination: None, .. }
-            | TerminatorKind::Abort
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::FalseEdges { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Return
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable => {}
-        }
-    }
-
-    fn terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        terminator: &mir::Terminator<'tcx>,
-        loc: Location,
-    ) {
-        match &terminator.kind {
-            // For call terminators the destination requires storage for the call
-            // and after the call returns successfully, but not after a panic.
-            // Since `propagate_call_unwind` doesn't exist, we have to kill the
-            // destination here, and then gen it again in `call_return_effect`.
-            TerminatorKind::Call { destination: Some((place, _)), .. } => {
-                trans.kill(place.local);
-            }
-
-            // Nothing to do for these. Match exhaustively so this fails to compile when new
-            // variants are added.
-            TerminatorKind::Call { destination: None, .. }
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::Abort
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::FalseEdges { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::InlineAsm { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Return
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable => {}
-        }
-
-        self.check_for_move(trans, loc);
-    }
-
-    fn call_return_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _block: BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
-    ) {
-        trans.gen(return_place.local);
-    }
-
-    fn yield_resume_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _resume_block: BasicBlock,
-        resume_place: mir::Place<'tcx>,
-    ) {
-        trans.gen(resume_place.local);
-    }
-}
-
-impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
-    /// Kill locals that are fully moved and have not been borrowed.
-    fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) {
-        let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals };
-        visitor.visit_location(&self.body, loc);
-    }
-}
-
-impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> {
-    /// bottom = dead
-    const BOTTOM_VALUE: bool = false;
-}
-
-struct MoveVisitor<'a, 'mir, 'tcx, T> {
-    borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
-    trans: &'a mut T,
-}
-
-impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T>
-where
-    T: GenKill<Local>,
-{
-    fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) {
-        if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
-            let mut borrowed_locals = self.borrowed_locals.borrow_mut();
-            borrowed_locals.seek_before_primary_effect(loc);
-            if !borrowed_locals.contains(*local) {
-                self.trans.kill(*local);
-            }
-        }
-    }
-}
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index eba4dd3..4f91257 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -651,7 +651,7 @@
         M::after_stack_push(self)?;
         info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance);
 
-        if self.stack().len() > *self.tcx.sess.recursion_limit.get() {
+        if self.stack().len() > self.tcx.sess.recursion_limit() {
             throw_exhaust!(StackFrameLimitReached)
         } else {
             Ok(())
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 42b969c..fc4be82a 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -219,7 +219,10 @@
                 let place = self.deref_operand(args[0])?;
                 let discr_val = self.read_discriminant(place.into())?.0;
                 let scalar = match dest.layout.ty.kind {
-                    ty::Int(_) => Scalar::from_int(discr_val as i128, dest.layout.size),
+                    ty::Int(_) => Scalar::from_int(
+                        self.sign_extend(discr_val, dest.layout) as i128,
+                        dest.layout.size,
+                    ),
                     ty::Uint(_) => Scalar::from_uint(discr_val, dest.layout.size),
                     _ => bug!("invalid `discriminant_value` return layout: {:?}", dest.layout),
                 };
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index f602064..c83555d 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -366,7 +366,7 @@
         let place = try_validation!(
             self.ecx.ref_to_mplace(value),
             self.path,
-            err_ub!(InvalidUninitBytes(..)) => { "uninitialized {}", kind },
+            err_ub!(InvalidUninitBytes { .. }) => { "uninitialized {}", kind },
         );
         if place.layout.is_unsized() {
             self.check_wide_ptr_meta(place.meta, place.layout)?;
@@ -514,7 +514,7 @@
                 let place = try_validation!(
                     self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?),
                     self.path,
-                    err_ub!(InvalidUninitBytes(..)) => { "uninitialized raw pointer" },
+                    err_ub!(InvalidUninitBytes { .. } ) => { "uninitialized raw pointer" },
                 );
                 if place.layout.is_unsized() {
                     self.check_wide_ptr_meta(place.meta, place.layout)?;
@@ -592,7 +592,7 @@
         let value = try_validation!(
             value.not_undef(),
             self.path,
-            err_ub!(InvalidUninitBytes(..)) => { "{}", value }
+            err_ub!(InvalidUninitBytes { .. }) => { "{}", value }
                 expected { "something {}", wrapping_range_format(valid_range, max_hi) },
         );
         let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) {
@@ -803,12 +803,14 @@
                         // For some errors we might be able to provide extra information.
                         // (This custom logic does not fit the `try_validation!` macro.)
                         match err.kind {
-                            err_ub!(InvalidUninitBytes(Some(ptr))) => {
+                            err_ub!(InvalidUninitBytes(Some(access))) => {
                                 // Some byte was uninitialized, determine which
                                 // element that byte belongs to so we can
                                 // provide an index.
-                                let i = usize::try_from(ptr.offset.bytes() / layout.size.bytes())
-                                    .unwrap();
+                                let i = usize::try_from(
+                                    access.uninit_ptr.offset.bytes() / layout.size.bytes(),
+                                )
+                                .unwrap();
                                 self.path.push(PathElem::ArrayElem(i));
 
                                 throw_validation_failure!(self.path, { "uninitialized bytes" })
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 925b8d3..081f643 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -430,7 +430,7 @@
     // Code that needs to instantiate the same function recursively
     // more than the recursion limit is assumed to be causing an
     // infinite expansion.
-    if adjusted_recursion_depth > *tcx.sess.recursion_limit.get() {
+    if adjusted_recursion_depth > tcx.sess.recursion_limit() {
         let error = format!("reached the recursion limit while instantiating `{}`", instance);
         if let Some(def_id) = def_id.as_local() {
             let hir_id = tcx.hir().as_local_hir_id(def_id);
@@ -463,8 +463,7 @@
     // which means that rustc basically hangs.
     //
     // Bail out in these cases to avoid that bad user experience.
-    let type_length_limit = *tcx.sess.type_length_limit.get();
-    if type_length > type_length_limit {
+    if type_length > tcx.sess.type_length_limit() {
         // The instance name is already known to be too long for rustc.
         // Show only the first and last 32 characters to avoid blasting
         // the user's terminal with thousands of lines of type-name.
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 4bf2adc..50a882a 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -50,7 +50,7 @@
 //! Otherwise it drops all the values in scope at the last suspension point.
 
 use crate::dataflow::impls::{
-    MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
+    MaybeBorrowedLocals, MaybeInitializedLocals, MaybeLiveLocals, MaybeStorageLive,
 };
 use crate::dataflow::{self, Analysis};
 use crate::transform::no_landing_pads::no_landing_pads;
@@ -266,7 +266,7 @@
 
     // Create a statement which reads the discriminant into a temporary
     fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) {
-        let temp_decl = LocalDecl::new(self.tcx.types.isize, body.span).internal();
+        let temp_decl = LocalDecl::new(self.discr_ty, body.span).internal();
         let local_decls_len = body.local_decls.push(temp_decl);
         let temp = Place::from(local_decls_len);
 
@@ -444,86 +444,80 @@
     movable: bool,
 ) -> LivenessInfo {
     let def_id = source.def_id();
-    let body_ref: &Body<'_> = &body;
 
     // Calculate when MIR locals have live storage. This gives us an upper bound of their
     // lifetimes.
     let mut storage_live = MaybeStorageLive::new(always_live_locals.clone())
-        .into_engine(tcx, body_ref, def_id)
+        .into_engine(tcx, body, def_id)
         .iterate_to_fixpoint()
-        .into_results_cursor(body_ref);
+        .into_results_cursor(body);
 
-    // Calculate the MIR locals which have been previously
-    // borrowed (even if they are still active).
-    let borrowed_locals_results =
-        MaybeBorrowedLocals::all_borrows().into_engine(tcx, body_ref, def_id).iterate_to_fixpoint();
-
-    let mut borrowed_locals_cursor =
-        dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
-
-    // Calculate the MIR locals that we actually need to keep storage around
-    // for.
-    let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results)
-        .into_engine(tcx, body_ref, def_id)
-        .iterate_to_fixpoint();
-    let mut requires_storage_cursor =
-        dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
-
-    // Calculate the liveness of MIR locals ignoring borrows.
-    let mut liveness = MaybeLiveLocals
-        .into_engine(tcx, body_ref, def_id)
+    let mut init = MaybeInitializedLocals
+        .into_engine(tcx, body, def_id)
         .iterate_to_fixpoint()
-        .into_results_cursor(body_ref);
+        .into_results_cursor(body);
+
+    let mut live = MaybeLiveLocals
+        .into_engine(tcx, body, def_id)
+        .iterate_to_fixpoint()
+        .into_results_cursor(body);
+
+    let mut borrowed = MaybeBorrowedLocals::all_borrows()
+        .into_engine(tcx, body, def_id)
+        .iterate_to_fixpoint()
+        .into_results_cursor(body);
+
+    // Liveness across yield points is determined by the following boolean equation, where `live`,
+    // `init` and `borrowed` come from dataflow and `movable` is a property of the generator.
+    // Movable generators do not allow borrows to live across yield points, so they don't need to
+    // store a local simply because it is borrowed.
+    //
+    //    live_across_yield := (live & init) | (!movable & borrowed)
+    //
+    let mut locals_live_across_yield_point = |block| {
+        live.seek_to_block_end(block);
+        let mut live_locals = live.get().clone();
+
+        init.seek_to_block_end(block);
+        live_locals.intersect(init.get());
+
+        if !movable {
+            borrowed.seek_to_block_end(block);
+            live_locals.union(borrowed.get());
+        }
+
+        live_locals
+    };
 
     let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks());
     let mut live_locals_at_suspension_points = Vec::new();
     let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len());
 
     for (block, data) in body.basic_blocks().iter_enumerated() {
-        if let TerminatorKind::Yield { .. } = data.terminator().kind {
-            let loc = Location { block, statement_index: data.statements.len() };
-
-            liveness.seek_to_block_end(block);
-            let mut live_locals = liveness.get().clone();
-
-            if !movable {
-                // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
-                // This is correct for movable generators since borrows cannot live across
-                // suspension points. However for immovable generators we need to account for
-                // borrows, so we conseratively assume that all borrowed locals are live until
-                // we find a StorageDead statement referencing the locals.
-                // To do this we just union our `liveness` result with `borrowed_locals`, which
-                // contains all the locals which has been borrowed before this suspension point.
-                // If a borrow is converted to a raw reference, we must also assume that it lives
-                // forever. Note that the final liveness is still bounded by the storage liveness
-                // of the local, which happens using the `intersect` operation below.
-                borrowed_locals_cursor.seek_before_primary_effect(loc);
-                live_locals.union(borrowed_locals_cursor.get());
-            }
-
-            // Store the storage liveness for later use so we can restore the state
-            // after a suspension point
-            storage_live.seek_before_primary_effect(loc);
-            storage_liveness_map[block] = Some(storage_live.get().clone());
-
-            // Locals live are live at this point only if they are used across
-            // suspension points (the `liveness` variable)
-            // and their storage is required (the `storage_required` variable)
-            requires_storage_cursor.seek_before_primary_effect(loc);
-            live_locals.intersect(requires_storage_cursor.get());
-
-            // The generator argument is ignored.
-            live_locals.remove(SELF_ARG);
-
-            debug!("loc = {:?}, live_locals = {:?}", loc, live_locals);
-
-            // Add the locals live at this suspension point to the set of locals which live across
-            // any suspension points
-            live_locals_at_any_suspension_point.union(&live_locals);
-
-            live_locals_at_suspension_points.push(live_locals);
+        if !matches!(data.terminator().kind, TerminatorKind::Yield { ..  }) {
+            continue;
         }
+
+        // Store the storage liveness for later use so we can restore the state
+        // after a suspension point
+        storage_live.seek_to_block_end(block);
+        storage_liveness_map[block] = Some(storage_live.get().clone());
+
+        let mut live_locals = locals_live_across_yield_point(block);
+
+        // The combination of `MaybeInitializedLocals` and `MaybeBorrowedLocals` should be strictly
+        // more precise than `MaybeStorageLive` because they handle `StorageDead` themselves. This
+        // assumes that the MIR forbids locals from being initialized/borrowed before reaching
+        // `StorageLive`.
+        debug_assert!(storage_live.get().superset(&live_locals));
+
+        // Ignore the generator's `self` argument since it is handled seperately.
+        live_locals.remove(SELF_ARG);
+        debug!("block = {:?}, live_locals = {:?}", block, live_locals);
+        live_locals_at_any_suspension_point.union(&live_locals);
+        live_locals_at_suspension_points.push(live_locals);
     }
+
     debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point);
 
     // Renumber our liveness_map bitsets to include only the locals we are
@@ -534,10 +528,11 @@
         .collect();
 
     let storage_conflicts = compute_storage_conflicts(
-        body_ref,
+        body,
         &live_locals_at_any_suspension_point,
         always_live_locals.clone(),
-        requires_storage_results,
+        init,
+        borrowed,
     );
 
     LivenessInfo {
@@ -569,6 +564,37 @@
     out
 }
 
+/// Record conflicts between locals at the current dataflow cursor positions.
+///
+/// You need to seek the cursors before calling this function.
+fn record_conflicts_at_curr_loc(
+    local_conflicts: &mut BitMatrix<Local, Local>,
+    init: &dataflow::ResultsCursor<'mir, 'tcx, MaybeInitializedLocals>,
+    borrowed: &dataflow::ResultsCursor<'mir, 'tcx, MaybeBorrowedLocals>,
+) {
+    // A local requires storage if it is initialized or borrowed. For now, a local
+    // becomes uninitialized if it is moved from, but is still considered "borrowed".
+    //
+    //     requires_storage := init | borrowed
+    //
+    // Just like when determining what locals are live at yield points, there is no need
+    // to look at storage liveness here, since `init | borrowed` is strictly more precise.
+    //
+    // FIXME: This function is called in a loop, so it might be better to pass in a temporary
+    // bitset rather than cloning here.
+    let mut requires_storage = init.get().clone();
+    requires_storage.union(borrowed.get());
+
+    for local in requires_storage.iter() {
+        local_conflicts.union_row_with(&requires_storage, local);
+    }
+
+    // `>1` because the `self` argument always requires storage.
+    if requires_storage.count() > 1 {
+        trace!("requires_storage={:?}", requires_storage);
+    }
+}
+
 /// For every saved local, looks for which locals are StorageLive at the same
 /// time. Generates a bitset for every local of all the other locals that may be
 /// StorageLive simultaneously with that local. This is used in the layout
@@ -577,30 +603,45 @@
     body: &'mir Body<'tcx>,
     stored_locals: &BitSet<Local>,
     always_live_locals: storage::AlwaysLiveLocals,
-    requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
+    mut init: dataflow::ResultsCursor<'mir, 'tcx, MaybeInitializedLocals>,
+    mut borrowed: dataflow::ResultsCursor<'mir, 'tcx, MaybeBorrowedLocals>,
 ) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
+    debug!("compute_storage_conflicts({:?})", body.span);
     assert_eq!(body.local_decls.len(), stored_locals.domain_size());
 
-    debug!("compute_storage_conflicts({:?})", body.span);
-    debug!("always_live = {:?}", always_live_locals);
+    // Locals that are always live conflict with all other locals.
+    //
+    // FIXME: Why do we need to handle locals without `Storage{Live,Dead}` specially here?
+    // Shouldn't it be enough to know whether they are initialized?
+    let always_live_locals = always_live_locals.into_inner();
+    let mut local_conflicts = BitMatrix::from_row_n(&always_live_locals, body.local_decls.len());
 
-    // Locals that are always live or ones that need to be stored across
-    // suspension points are not eligible for overlap.
-    let mut ineligible_locals = always_live_locals.into_inner();
-    ineligible_locals.intersect(stored_locals);
+    // Visit every reachable statement and terminator. The exact order does not matter. When two
+    // locals are live at the same point in time, add an entry in the conflict matrix.
+    for (block, data) in traversal::preorder(body) {
+        // Ignore unreachable blocks.
+        if data.terminator().kind == TerminatorKind::Unreachable {
+            continue;
+        }
 
-    // Compute the storage conflicts for all eligible locals.
-    let mut visitor = StorageConflictVisitor {
-        body,
-        stored_locals: &stored_locals,
-        local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
-    };
+        // Observe the dataflow state *before* all possible locations (statement or terminator) in
+        // each basic block...
+        for statement_index in 0..=data.statements.len() {
+            let loc = Location { block, statement_index };
+            trace!("record conflicts at {:?}", loc);
+            init.seek_before_primary_effect(loc);
+            borrowed.seek_before_primary_effect(loc);
+            record_conflicts_at_curr_loc(&mut local_conflicts, &init, &borrowed);
+        }
 
-    // Visit only reachable basic blocks. The exact order is not important.
-    let reachable_blocks = traversal::preorder(body).map(|(bb, _)| bb);
-    requires_storage.visit_with(body, reachable_blocks, &mut visitor);
-
-    let local_conflicts = visitor.local_conflicts;
+        // ...and then observe the state *after* the terminator effect is applied. As long as
+        // neither `init` nor `borrowed` has a "before" effect, we will observe all possible
+        // dataflow states here or in the loop above.
+        trace!("record conflicts at end of {:?}", block);
+        init.seek_to_block_end(block);
+        borrowed.seek_to_block_end(block);
+        record_conflicts_at_curr_loc(&mut local_conflicts, &init, &borrowed);
+    }
 
     // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal).
     //
@@ -612,7 +653,7 @@
     let mut storage_conflicts = BitMatrix::new(stored_locals.count(), stored_locals.count());
     for (idx_a, local_a) in stored_locals.iter().enumerate() {
         let saved_local_a = GeneratorSavedLocal::new(idx_a);
-        if ineligible_locals.contains(local_a) {
+        if always_live_locals.contains(local_a) {
             // Conflicts with everything.
             storage_conflicts.insert_all_into_row(saved_local_a);
         } else {
@@ -628,56 +669,6 @@
     storage_conflicts
 }
 
-struct StorageConflictVisitor<'mir, 'tcx, 's> {
-    body: &'mir Body<'tcx>,
-    stored_locals: &'s BitSet<Local>,
-    // FIXME(tmandry): Consider using sparse bitsets here once we have good
-    // benchmarks for generators.
-    local_conflicts: BitMatrix<Local, Local>,
-}
-
-impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> {
-    type FlowState = BitSet<Local>;
-
-    fn visit_statement_before_primary_effect(
-        &mut self,
-        state: &Self::FlowState,
-        _statement: &'mir Statement<'tcx>,
-        loc: Location,
-    ) {
-        self.apply_state(state, loc);
-    }
-
-    fn visit_terminator_before_primary_effect(
-        &mut self,
-        state: &Self::FlowState,
-        _terminator: &'mir Terminator<'tcx>,
-        loc: Location,
-    ) {
-        self.apply_state(state, loc);
-    }
-}
-
-impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> {
-    fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
-        // Ignore unreachable blocks.
-        if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable {
-            return;
-        }
-
-        let mut eligible_storage_live = flow_state.clone();
-        eligible_storage_live.intersect(&self.stored_locals);
-
-        for local in eligible_storage_live.iter() {
-            self.local_conflicts.union_row_with(&eligible_storage_live, local);
-        }
-
-        if eligible_storage_live.count() > 1 {
-            trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live);
-        }
-    }
-}
-
 fn compute_layout<'tcx>(
     tcx: TyCtxt<'tcx>,
     source: MirSource<'tcx>,
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 0750284..ead530b 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -3,7 +3,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, adjustment::PointerCast, Predicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use std::borrow::Cow;
@@ -23,28 +23,30 @@
     loop {
         let predicates = tcx.predicates_of(current);
         for (predicate, _) in predicates.predicates {
-            match predicate {
-                Predicate::RegionOutlives(_)
-                | Predicate::TypeOutlives(_)
-                | Predicate::WellFormed(_)
-                | Predicate::Projection(_)
-                | Predicate::ConstEvaluatable(..)
-                | Predicate::ConstEquate(..) => continue,
-                Predicate::ObjectSafe(_) => {
+            match predicate.kind() {
+                ty::PredicateKind::RegionOutlives(_)
+                | ty::PredicateKind::TypeOutlives(_)
+                | ty::PredicateKind::WellFormed(_)
+                | ty::PredicateKind::Projection(_)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..) => continue,
+                ty::PredicateKind::ObjectSafe(_) => {
                     bug!("object safe predicate on function: {:#?}", predicate)
                 }
-                Predicate::ClosureKind(..) => {
+                ty::PredicateKind::ClosureKind(..) => {
                     bug!("closure kind predicate on function: {:#?}", predicate)
                 }
-                Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
-                Predicate::Trait(pred, constness) => {
+                ty::PredicateKind::Subtype(_) => {
+                    bug!("subtype predicate on function: {:#?}", predicate)
+                }
+                &ty::PredicateKind::Trait(pred, constness) => {
                     if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                         continue;
                     }
                     match pred.skip_binder().self_ty().kind {
                         ty::Param(ref p) => {
                             // Allow `T: ?const Trait`
-                            if *constness == hir::Constness::NotConst
+                            if constness == hir::Constness::NotConst
                                 && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out)
                             {
                                 continue;
diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs
index f6941d3..626e531 100644
--- a/src/librustc_mir_build/hair/pattern/_match.rs
+++ b/src/librustc_mir_build/hair/pattern/_match.rs
@@ -1,5 +1,5 @@
-/// Note: most tests relevant to this file can be found (at the time of writing)
-/// in src/tests/ui/pattern/usefulness.
+/// Note: most of the tests relevant to this file can be found (at the time of writing) in
+/// src/tests/ui/pattern/usefulness.
 ///
 /// This file includes the logic for exhaustiveness and usefulness checking for
 /// pattern-matching. Specifically, given a list of patterns for a type, we can
@@ -13,6 +13,8 @@
 /// summarise the algorithm here to hopefully save time and be a little clearer
 /// (without being so rigorous).
 ///
+/// # Premise
+///
 /// The core of the algorithm revolves about a "usefulness" check. In particular, we
 /// are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
 /// a matrix). `U(P, p)` represents whether, given an existing list of patterns
@@ -27,8 +29,51 @@
 /// pattern to those that have come before it doesn't increase the number of values
 /// we're matching).
 ///
+/// # Core concept
+///
+/// The idea that powers everything that is done in this file is the following: a value is made
+/// from a constructor applied to some fields. Examples of constructors are `Some`, `None`, `(,)`
+/// (the 2-tuple constructor), `Foo {..}` (the constructor for a struct `Foo`), and `2` (the
+/// constructor for the number `2`). Fields are just a (possibly empty) list of values.
+///
+/// Some of the constructors listed above might feel weird: `None` and `2` don't take any
+/// arguments. This is part of what makes constructors so general: we will consider plain values
+/// like numbers and string literals to be constructors that take no arguments, also called "0-ary
+/// constructors"; they are the simplest case of constructors. This allows us to see any value as
+/// made up from a tree of constructors, each having a given number of children. For example:
+/// `(None, Ok(0))` is made from 4 different constructors.
+///
+/// This idea can be extended to patterns: a pattern captures a set of possible values, and we can
+/// describe this set using constructors. For example, `Err(_)` captures all values of the type
+/// `Result<T, E>` that start with the `Err` constructor (for some choice of `T` and `E`). The
+/// wildcard `_` captures all values of the given type starting with any of the constructors for
+/// that type.
+///
+/// We use this to compute whether different patterns might capture a same value. Do the patterns
+/// `Ok("foo")` and `Err(_)` capture a common value? The answer is no, because the first pattern
+/// captures only values starting with the `Ok` constructor and the second only values starting
+/// with the `Err` constructor. Do the patterns `Some(42)` and `Some(1..10)` intersect? They might,
+/// since they both capture values starting with `Some`. To be certain, we need to dig under the
+/// `Some` constructor and continue asking the question. This is the main idea behind the
+/// exhaustiveness algorithm: by looking at patterns constructor-by-constructor, we can efficiently
+/// figure out if some new pattern might capture a value that hadn't been captured by previous
+/// patterns.
+///
+/// Constructors are represented by the `Constructor` enum, and its fields by the `Fields` enum.
+/// Most of the complexity of this file resides in transforming between patterns and
+/// (`Constructor`, `Fields`) pairs, handling all the special cases correctly.
+///
+/// Caveat: this constructors/fields distinction doesn't quite cover every Rust value. For example
+/// a value of type `Rc<u64>` doesn't fit this idea very well, nor do various other things.
+/// However, this idea covers most of the cases that are relevant to exhaustiveness checking.
+///
+///
+/// # Algorithm
+///
+/// Recall that `U(P, p)` represents whether, given an existing list of patterns (aka matrix) `P`,
+/// adding a new pattern `p` will cover previously-uncovered values of the type.
 /// During the course of the algorithm, the rows of the matrix won't just be individual patterns,
-/// but rather partially-deconstructed patterns in the form of a list of patterns. The paper
+/// but rather partially-deconstructed patterns in the form of a list of fields. The paper
 /// calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
 /// new pattern `p`.
 ///
@@ -242,7 +287,7 @@
 use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
 use rustc_middle::mir::Field;
 use rustc_middle::ty::layout::IntegerExt;
-use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt};
 use rustc_session::lint;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Integer, Size, VariantIdx};
@@ -441,13 +486,11 @@
         &self,
         cx: &mut MatchCheckCtxt<'p, 'tcx>,
         constructor: &Constructor<'tcx>,
-        ctor_wild_subpatterns: &'p [Pat<'tcx>],
+        ctor_wild_subpatterns: &Fields<'p, 'tcx>,
     ) -> Option<PatStack<'p, 'tcx>> {
-        let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns);
-        new_heads.map(|mut new_head| {
-            new_head.0.extend_from_slice(&self.0[1..]);
-            new_head
-        })
+        let new_fields =
+            specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns)?;
+        Some(new_fields.push_on_patstack(&self.0[1..]))
     }
 }
 
@@ -503,7 +546,7 @@
         &self,
         cx: &mut MatchCheckCtxt<'p, 'tcx>,
         constructor: &Constructor<'tcx>,
-        ctor_wild_subpatterns: &'p [Pat<'tcx>],
+        ctor_wild_subpatterns: &Fields<'p, 'tcx>,
     ) -> Matrix<'p, 'tcx> {
         self.0
             .iter()
@@ -593,7 +636,7 @@
         }
     }
 
-    // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
+    /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
     crate fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
         match ty.kind {
             ty::Adt(def, ..) => {
@@ -602,15 +645,6 @@
             _ => false,
         }
     }
-
-    // Returns whether the given variant is from another crate and has its fields declared
-    // `#[non_exhaustive]`.
-    fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool {
-        match ty.kind {
-            ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(),
-            _ => false,
-        }
-    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -722,10 +756,17 @@
     }
 }
 
+/// A value can be decomposed into a constructor applied to some fields. This struct represents
+/// the constructor. See also `Fields`.
+///
+/// `pat_constructor` retrieves the constructor corresponding to a pattern.
+/// `specialize_one_pattern` returns the list of fields corresponding to a pattern, given a
+/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
+/// `Fields`.
 #[derive(Clone, Debug, PartialEq)]
 enum Constructor<'tcx> {
-    /// The constructor of all patterns that don't vary by constructor,
-    /// e.g., struct patterns and fixed-length arrays.
+    /// The constructor for patterns that have a single constructor, like tuples, struct patterns
+    /// and fixed-length arrays.
     Single,
     /// Enum variants.
     Variant(DefId),
@@ -850,107 +891,10 @@
         }
     }
 
-    /// This returns one wildcard pattern for each argument to this constructor.
-    ///
-    /// This must be consistent with `apply`, `specialize_one_pattern`, and `arity`.
-    fn wildcard_subpatterns<'a>(
-        &self,
-        cx: &MatchCheckCtxt<'a, 'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Vec<Pat<'tcx>> {
-        debug!("wildcard_subpatterns({:#?}, {:?})", self, ty);
-
-        match self {
-            Single | Variant(_) => match ty.kind {
-                ty::Tuple(ref fs) => {
-                    fs.into_iter().map(|t| t.expect_ty()).map(Pat::wildcard_from_ty).collect()
-                }
-                ty::Ref(_, rty, _) => vec![Pat::wildcard_from_ty(rty)],
-                ty::Adt(adt, substs) => {
-                    if adt.is_box() {
-                        // Use T as the sub pattern type of Box<T>.
-                        vec![Pat::wildcard_from_ty(substs.type_at(0))]
-                    } else {
-                        let variant = &adt.variants[self.variant_index_for_adt(cx, adt)];
-                        let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(ty, variant);
-                        variant
-                            .fields
-                            .iter()
-                            .map(|field| {
-                                let is_visible = adt.is_enum()
-                                    || field.vis.is_accessible_from(cx.module, cx.tcx);
-                                let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs));
-                                match (is_visible, is_non_exhaustive, is_uninhabited) {
-                                    // Treat all uninhabited types in non-exhaustive variants as
-                                    // `TyErr`.
-                                    (_, true, true) => cx.tcx.types.err,
-                                    // Treat all non-visible fields as `TyErr`. They can't appear
-                                    // in any other pattern from this match (because they are
-                                    // private), so their type does not matter - but we don't want
-                                    // to know they are uninhabited.
-                                    (false, ..) => cx.tcx.types.err,
-                                    (true, ..) => {
-                                        let ty = field.ty(cx.tcx, substs);
-                                        match ty.kind {
-                                            // If the field type returned is an array of an unknown
-                                            // size return an TyErr.
-                                            ty::Array(_, len)
-                                                if len
-                                                    .try_eval_usize(cx.tcx, cx.param_env)
-                                                    .is_none() =>
-                                            {
-                                                cx.tcx.types.err
-                                            }
-                                            _ => ty,
-                                        }
-                                    }
-                                }
-                            })
-                            .map(Pat::wildcard_from_ty)
-                            .collect()
-                    }
-                }
-                _ => vec![],
-            },
-            Slice(_) => match ty.kind {
-                ty::Slice(ty) | ty::Array(ty, _) => {
-                    let arity = self.arity(cx, ty);
-                    (0..arity).map(|_| Pat::wildcard_from_ty(ty)).collect()
-                }
-                _ => bug!("bad slice pattern {:?} {:?}", self, ty),
-            },
-            ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => vec![],
-        }
-    }
-
-    /// This computes the arity of a constructor. The arity of a constructor
-    /// is how many subpattern patterns of that constructor should be expanded to.
-    ///
-    /// For instance, a tuple pattern `(_, 42, Some([]))` has the arity of 3.
-    /// A struct pattern's arity is the number of fields it contains, etc.
-    ///
-    /// This must be consistent with `wildcard_subpatterns`, `specialize_one_pattern`, and `apply`.
-    fn arity<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> u64 {
-        debug!("Constructor::arity({:#?}, {:?})", self, ty);
-        match self {
-            Single | Variant(_) => match ty.kind {
-                ty::Tuple(ref fs) => fs.len() as u64,
-                ty::Slice(..) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty),
-                ty::Ref(..) => 1,
-                ty::Adt(adt, _) => {
-                    adt.variants[self.variant_index_for_adt(cx, adt)].fields.len() as u64
-                }
-                _ => 0,
-            },
-            Slice(slice) => slice.arity(),
-            ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => 0,
-        }
-    }
-
     /// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
     /// must have as many elements as this constructor's arity.
     ///
-    /// This must be consistent with `wildcard_subpatterns`, `specialize_one_pattern`, and `arity`.
+    /// This is roughly the inverse of `specialize_one_pattern`.
     ///
     /// Examples:
     /// `self`: `Constructor::Single`
@@ -962,13 +906,13 @@
     /// `ty`: `Option<bool>`
     /// `pats`: `[false]`
     /// returns `Some(false)`
-    fn apply<'a>(
+    fn apply<'p>(
         &self,
-        cx: &MatchCheckCtxt<'a, 'tcx>,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
         ty: Ty<'tcx>,
-        pats: impl IntoIterator<Item = Pat<'tcx>>,
+        fields: Fields<'p, 'tcx>,
     ) -> Pat<'tcx> {
-        let mut subpatterns = pats.into_iter();
+        let mut subpatterns = fields.all_patterns();
 
         let pat = match self {
             Single | Variant(_) => match ty.kind {
@@ -1033,8 +977,263 @@
 
     /// Like `apply`, but where all the subpatterns are wildcards `_`.
     fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
-        let subpatterns = self.wildcard_subpatterns(cx, ty).into_iter().rev();
-        self.apply(cx, ty, subpatterns)
+        self.apply(cx, ty, Fields::wildcards(cx, self, ty))
+    }
+}
+
+/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
+/// `Fields` struct. This struct represents such a potentially-hidden field. When a field is hidden
+/// we still keep its type around.
+#[derive(Debug, Copy, Clone)]
+enum FilteredField<'p, 'tcx> {
+    Kept(&'p Pat<'tcx>),
+    Hidden(Ty<'tcx>),
+}
+
+impl<'p, 'tcx> FilteredField<'p, 'tcx> {
+    fn kept(self) -> Option<&'p Pat<'tcx>> {
+        match self {
+            FilteredField::Kept(p) => Some(p),
+            FilteredField::Hidden(_) => None,
+        }
+    }
+
+    fn to_pattern(self) -> Pat<'tcx> {
+        match self {
+            FilteredField::Kept(p) => p.clone(),
+            FilteredField::Hidden(ty) => Pat::wildcard_from_ty(ty),
+        }
+    }
+}
+
+/// A value can be decomposed into a constructor applied to some fields. This struct represents
+/// those fields, generalized to allow patterns in each field. See also `Constructor`.
+///
+/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is
+/// uninhabited. For that, we filter these fields out of the matrix. This is subtle because we
+/// still need to have those fields back when going to/from a `Pat`. Most of this is handled
+/// automatically in `Fields`, but when constructing or deconstructing `Fields` you need to be
+/// careful. As a rule, when going to/from the matrix, use the filtered field list; when going
+/// to/from `Pat`, use the full field list.
+/// This filtering is uncommon in practice, because uninhabited fields are rarely used, so we avoid
+/// it when possible to preserve performance.
+#[derive(Debug, Clone)]
+enum Fields<'p, 'tcx> {
+    /// Lists of patterns that don't contain any filtered fields.
+    /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and
+    /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril)
+    /// have not measured if it really made a difference.
+    Slice(&'p [Pat<'tcx>]),
+    Vec(SmallVec<[&'p Pat<'tcx>; 2]>),
+    /// Patterns where some of the fields need to be hidden. `len` caches the number of non-hidden
+    /// fields.
+    Filtered {
+        fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>,
+        len: usize,
+    },
+}
+
+impl<'p, 'tcx> Fields<'p, 'tcx> {
+    fn empty() -> Self {
+        Fields::Slice(&[])
+    }
+
+    /// Construct a new `Fields` from the given pattern. Must not be used if the pattern is a field
+    /// of a struct/tuple/variant.
+    fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self {
+        Fields::Slice(std::slice::from_ref(pat))
+    }
+
+    /// Construct a new `Fields` from the given patterns. You must be sure those patterns can't
+    /// contain fields that need to be filtered out. When in doubt, prefer `replace_fields`.
+    fn from_slice_unfiltered(pats: &'p [Pat<'tcx>]) -> Self {
+        Fields::Slice(pats)
+    }
+
+    /// Convenience; internal use.
+    fn wildcards_from_tys(
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        tys: impl IntoIterator<Item = Ty<'tcx>>,
+    ) -> Self {
+        let wilds = tys.into_iter().map(Pat::wildcard_from_ty);
+        let pats = cx.pattern_arena.alloc_from_iter(wilds);
+        Fields::Slice(pats)
+    }
+
+    /// Creates a new list of wildcard fields for a given constructor.
+    fn wildcards(
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        constructor: &Constructor<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Self {
+        debug!("Fields::wildcards({:#?}, {:?})", constructor, ty);
+        let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty));
+
+        match constructor {
+            Single | Variant(_) => match ty.kind {
+                ty::Tuple(ref fs) => {
+                    Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty()))
+                }
+                ty::Ref(_, rty, _) => Fields::from_single_pattern(wildcard_from_ty(rty)),
+                ty::Adt(adt, substs) => {
+                    if adt.is_box() {
+                        // Use T as the sub pattern type of Box<T>.
+                        Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0)))
+                    } else {
+                        let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)];
+                        // Whether we must not match the fields of this variant exhaustively.
+                        let is_non_exhaustive =
+                            variant.is_field_list_non_exhaustive() && !adt.did.is_local();
+                        let field_tys = variant.fields.iter().map(|field| field.ty(cx.tcx, substs));
+                        // In the following cases, we don't need to filter out any fields. This is
+                        // the vast majority of real cases, since uninhabited fields are uncommon.
+                        let has_no_hidden_fields = (adt.is_enum() && !is_non_exhaustive)
+                            || !field_tys.clone().any(|ty| cx.is_uninhabited(ty));
+
+                        if has_no_hidden_fields {
+                            Fields::wildcards_from_tys(cx, field_tys)
+                        } else {
+                            let mut len = 0;
+                            let fields = variant
+                                .fields
+                                .iter()
+                                .map(|field| {
+                                    let ty = field.ty(cx.tcx, substs);
+                                    let is_visible = adt.is_enum()
+                                        || field.vis.is_accessible_from(cx.module, cx.tcx);
+                                    let is_uninhabited = cx.is_uninhabited(ty);
+
+                                    // In the cases of either a `#[non_exhaustive]` field list
+                                    // or a non-public field, we hide uninhabited fields in
+                                    // order not to reveal the uninhabitedness of the whole
+                                    // variant.
+                                    if is_uninhabited && (!is_visible || is_non_exhaustive) {
+                                        FilteredField::Hidden(ty)
+                                    } else {
+                                        len += 1;
+                                        FilteredField::Kept(wildcard_from_ty(ty))
+                                    }
+                                })
+                                .collect();
+                            Fields::Filtered { fields, len }
+                        }
+                    }
+                }
+                _ => Fields::empty(),
+            },
+            Slice(slice) => match ty.kind {
+                ty::Slice(ty) | ty::Array(ty, _) => {
+                    let arity = slice.arity();
+                    Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
+                }
+                _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
+            },
+            ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => Fields::empty(),
+        }
+    }
+
+    fn len(&self) -> usize {
+        match self {
+            Fields::Slice(pats) => pats.len(),
+            Fields::Vec(pats) => pats.len(),
+            Fields::Filtered { len, .. } => *len,
+        }
+    }
+
+    /// Returns the complete list of patterns, including hidden fields.
+    fn all_patterns(self) -> impl Iterator<Item = Pat<'tcx>> {
+        let pats: SmallVec<[_; 2]> = match self {
+            Fields::Slice(pats) => pats.iter().cloned().collect(),
+            Fields::Vec(pats) => pats.into_iter().cloned().collect(),
+            Fields::Filtered { fields, .. } => {
+                // We don't skip any fields here.
+                fields.into_iter().map(|p| p.to_pattern()).collect()
+            }
+        };
+        pats.into_iter()
+    }
+
+    /// Overrides some of the fields with the provided patterns. Exactly like
+    /// `replace_fields_indexed`, except that it takes `FieldPat`s as input.
+    fn replace_with_fieldpats(
+        &self,
+        new_pats: impl IntoIterator<Item = &'p FieldPat<'tcx>>,
+    ) -> Self {
+        self.replace_fields_indexed(
+            new_pats.into_iter().map(|pat| (pat.field.index(), &pat.pattern)),
+        )
+    }
+
+    /// Overrides some of the fields with the provided patterns. This is used when a pattern
+    /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start with a
+    /// `Fields` that is just one wildcard per field of the `Foo` struct, and override the entry
+    /// corresponding to `field1` with the pattern `Some(_)`. This is also used for slice patterns
+    /// for the same reason.
+    fn replace_fields_indexed(
+        &self,
+        new_pats: impl IntoIterator<Item = (usize, &'p Pat<'tcx>)>,
+    ) -> Self {
+        let mut fields = self.clone();
+        if let Fields::Slice(pats) = fields {
+            fields = Fields::Vec(pats.iter().collect());
+        }
+
+        match &mut fields {
+            Fields::Vec(pats) => {
+                for (i, pat) in new_pats {
+                    pats[i] = pat
+                }
+            }
+            Fields::Filtered { fields, .. } => {
+                for (i, pat) in new_pats {
+                    if let FilteredField::Kept(p) = &mut fields[i] {
+                        *p = pat
+                    }
+                }
+            }
+            Fields::Slice(_) => unreachable!(),
+        }
+        fields
+    }
+
+    /// Replaces contained fields with the given filtered list of patterns, e.g. taken from the
+    /// matrix. There must be `len()` patterns in `pats`.
+    fn replace_fields(
+        &self,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        pats: impl IntoIterator<Item = Pat<'tcx>>,
+    ) -> Self {
+        let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats);
+
+        match self {
+            Fields::Filtered { fields, len } => {
+                let mut pats = pats.iter();
+                let mut fields = fields.clone();
+                for f in &mut fields {
+                    if let FilteredField::Kept(p) = f {
+                        // We take one input pattern for each `Kept` field, in order.
+                        *p = pats.next().unwrap();
+                    }
+                }
+                Fields::Filtered { fields, len: *len }
+            }
+            _ => Fields::Slice(pats),
+        }
+    }
+
+    fn push_on_patstack(self, stack: &[&'p Pat<'tcx>]) -> PatStack<'p, 'tcx> {
+        let pats: SmallVec<_> = match self {
+            Fields::Slice(pats) => pats.iter().chain(stack.iter().copied()).collect(),
+            Fields::Vec(mut pats) => {
+                pats.extend_from_slice(stack);
+                pats
+            }
+            Fields::Filtered { fields, .. } => {
+                // We skip hidden fields here
+                fields.into_iter().filter_map(|p| p.kept()).chain(stack.iter().copied()).collect()
+            }
+        };
+        PatStack::from_vec(pats)
     }
 }
 
@@ -1064,15 +1263,16 @@
 
     fn apply_constructor(
         self,
-        cx: &MatchCheckCtxt<'_, 'tcx>,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
         ctor: &Constructor<'tcx>,
         ty: Ty<'tcx>,
+        ctor_wild_subpatterns: &Fields<'p, 'tcx>,
     ) -> Self {
         match self {
             UsefulWithWitness(witnesses) => UsefulWithWitness(
                 witnesses
                     .into_iter()
-                    .map(|witness| witness.apply_constructor(cx, &ctor, ty))
+                    .map(|witness| witness.apply_constructor(cx, &ctor, ty, ctor_wild_subpatterns))
                     .collect(),
             ),
             x => x,
@@ -1192,17 +1392,19 @@
     ///
     /// left_ty: struct X { a: (bool, &'static str), b: usize}
     /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
-    fn apply_constructor<'a>(
+    fn apply_constructor<'p>(
         mut self,
-        cx: &MatchCheckCtxt<'a, 'tcx>,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
         ctor: &Constructor<'tcx>,
         ty: Ty<'tcx>,
+        ctor_wild_subpatterns: &Fields<'p, 'tcx>,
     ) -> Self {
-        let arity = ctor.arity(cx, ty);
         let pat = {
-            let len = self.0.len() as u64;
-            let pats = self.0.drain((len - arity) as usize..).rev();
-            ctor.apply(cx, ty, pats)
+            let len = self.0.len();
+            let arity = ctor_wild_subpatterns.len();
+            let pats = self.0.drain((len - arity)..).rev();
+            let fields = ctor_wild_subpatterns.replace_fields(cx, pats);
+            ctor.apply(cx, ty, fields)
         };
 
         self.0.push(pat);
@@ -1600,11 +1802,7 @@
 /// to a set of such vectors `m` - this is defined as there being a set of
 /// inputs that will match `v` but not any of the sets in `m`.
 ///
-/// All the patterns at each column of the `matrix ++ v` matrix must
-/// have the same type, except that wildcard (PatKind::Wild) patterns
-/// with type `TyErr` are also allowed, even if the "type of the column"
-/// is not `TyErr`. That is used to represent private fields, as using their
-/// real type would assert that they are inhabited.
+/// All the patterns at each column of the `matrix ++ v` matrix must have the same type.
 ///
 /// This is used both for reachability checking (if a pattern isn't useful in
 /// relation to preceding patterns, it is not reachable) and exhaustiveness
@@ -1668,34 +1866,7 @@
         return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
     }
 
-    let (ty, span) = matrix
-        .heads()
-        .map(|r| (r.ty, r.span))
-        .find(|(ty, _)| !ty.references_error())
-        .unwrap_or((v.head().ty, v.head().span));
-    let pcx = PatCtxt {
-        // TyErr is used to represent the type of wildcard patterns matching
-        // against inaccessible (private) fields of structs, so that we won't
-        // be able to observe whether the types of the struct's fields are
-        // inhabited.
-        //
-        // If the field is truly inaccessible, then all the patterns
-        // matching against it must be wildcard patterns, so its type
-        // does not matter.
-        //
-        // However, if we are matching against non-wildcard patterns, we
-        // need to know the real type of the field so we can specialize
-        // against it. This primarily occurs through constants - they
-        // can include contents for fields that are inaccessible at the
-        // location of the match. In that case, the field's type is
-        // inhabited - by the constant - so we can just use it.
-        //
-        // FIXME: this might lead to "unstable" behavior with macro hygiene
-        // introducing uninhabited patterns for inaccessible fields. We
-        // need to figure out how to model that.
-        ty,
-        span,
-    };
+    let pcx = PatCtxt { ty: v.head().ty, span: v.head().span };
 
     debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
 
@@ -1827,19 +1998,19 @@
     matrix: &Matrix<'p, 'tcx>,
     v: &PatStack<'p, 'tcx>,
     ctor: Constructor<'tcx>,
-    lty: Ty<'tcx>,
+    ty: Ty<'tcx>,
     witness_preference: WitnessPreference,
     hir_id: HirId,
     is_under_guard: bool,
 ) -> Usefulness<'tcx, 'p> {
-    debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
+    debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, ty);
 
-    let ctor_wild_subpatterns =
-        cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
-    let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
-    v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
+    // We cache the result of `Fields::wildcards` because it is used a lot.
+    let ctor_wild_subpatterns = Fields::wildcards(cx, &ctor, ty);
+    let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
+    v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
         .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false))
-        .map(|u| u.apply_constructor(cx, &ctor, lty))
+        .map(|u| u.apply_constructor(cx, &ctor, ty, &ctor_wild_subpatterns))
         .unwrap_or(NotUseful)
 }
 
@@ -2303,27 +2474,6 @@
     if intersects { Some(()) } else { None }
 }
 
-fn patterns_for_variant<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    subpatterns: &'p [FieldPat<'tcx>],
-    ctor_wild_subpatterns: &'p [Pat<'tcx>],
-    is_non_exhaustive: bool,
-) -> PatStack<'p, 'tcx> {
-    let mut result: SmallVec<_> = ctor_wild_subpatterns.iter().collect();
-
-    for subpat in subpatterns {
-        if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) {
-            result[subpat.field.index()] = &subpat.pattern;
-        }
-    }
-
-    debug!(
-        "patterns_for_variant({:#?}, {:#?}) = {:#?}",
-        subpatterns, ctor_wild_subpatterns, result
-    );
-    PatStack::from_vec(result)
-}
-
 /// This is the main specialization step. It expands the pattern
 /// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
 /// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
@@ -2333,37 +2483,40 @@
 /// different patterns.
 /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
 /// fields filled with wild patterns.
+///
+/// This is roughly the inverse of `Constructor::apply`.
 fn specialize_one_pattern<'p, 'tcx>(
     cx: &mut MatchCheckCtxt<'p, 'tcx>,
     pat: &'p Pat<'tcx>,
     constructor: &Constructor<'tcx>,
-    ctor_wild_subpatterns: &'p [Pat<'tcx>],
-) -> Option<PatStack<'p, 'tcx>> {
+    ctor_wild_subpatterns: &Fields<'p, 'tcx>,
+) -> Option<Fields<'p, 'tcx>> {
     if let NonExhaustive = constructor {
         // Only a wildcard pattern can match the special extra constructor
-        return if pat.is_wildcard() { Some(PatStack::default()) } else { None };
+        if !pat.is_wildcard() {
+            return None;
+        }
+        return Some(Fields::empty());
     }
 
     let result = match *pat.kind {
         PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
 
-        PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_subpatterns.iter().collect()),
+        PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_subpatterns.clone()),
 
         PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
             let variant = &adt_def.variants[variant_index];
-            let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant);
-            Some(Variant(variant.def_id))
-                .filter(|variant_constructor| variant_constructor == constructor)
-                .map(|_| {
-                    patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, is_non_exhaustive)
-                })
+            if constructor != &Variant(variant.def_id) {
+                return None;
+            }
+            Some(ctor_wild_subpatterns.replace_with_fieldpats(subpatterns))
         }
 
         PatKind::Leaf { ref subpatterns } => {
-            Some(patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, false))
+            Some(ctor_wild_subpatterns.replace_with_fieldpats(subpatterns))
         }
 
-        PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)),
+        PatKind::Deref { ref subpattern } => Some(Fields::from_single_pattern(subpattern)),
 
         PatKind::Constant { value } if constructor.is_slice() => {
             // We extract an `Option` for the pointer because slices of zero
@@ -2376,11 +2529,10 @@
                     // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce,
                     // the result would be exactly what we early return here.
                     if n == 0 {
-                        if ctor_wild_subpatterns.len() as u64 == 0 {
-                            return Some(PatStack::from_slice(&[]));
-                        } else {
+                        if ctor_wild_subpatterns.len() as u64 != n {
                             return None;
                         }
+                        return Some(Fields::empty());
                     }
                     match value.val {
                         ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
@@ -2414,24 +2566,26 @@
                     constructor,
                 ),
             };
-            if ctor_wild_subpatterns.len() as u64 == n {
-                // convert a constant slice/array pattern to a list of patterns.
-                let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
-                let ptr = Pointer::new(AllocId(0), offset);
-                (0..n)
-                    .map(|i| {
-                        let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
-                        let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?;
-                        let scalar = scalar.not_undef().ok()?;
-                        let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
-                        let pattern =
-                            Pat { ty, span: pat.span, kind: box PatKind::Constant { value } };
-                        Some(&*cx.pattern_arena.alloc(pattern))
-                    })
-                    .collect()
-            } else {
-                None
+            if ctor_wild_subpatterns.len() as u64 != n {
+                return None;
             }
+
+            // Convert a constant slice/array pattern to a list of patterns.
+            let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
+            let ptr = Pointer::new(AllocId(0), offset);
+            let pats = cx.pattern_arena.alloc_from_iter((0..n).filter_map(|i| {
+                let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
+                let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?;
+                let scalar = scalar.not_undef().ok()?;
+                let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
+                let pattern = Pat { ty, span: pat.span, kind: box PatKind::Constant { value } };
+                Some(pattern)
+            }));
+            // Ensure none of the dereferences failed.
+            if pats.len() as u64 != n {
+                return None;
+            }
+            Some(Fields::from_slice_unfiltered(pats))
         }
 
         PatKind::Constant { .. } | PatKind::Range { .. } => {
@@ -2439,50 +2593,39 @@
             // - Single value: add a row if the pattern contains the constructor.
             // - Range: add a row if the constructor intersects the pattern.
             if let IntRange(ctor) = constructor {
-                match IntRange::from_pat(cx.tcx, cx.param_env, pat) {
-                    Some(pat) => ctor.intersection(cx.tcx, &pat).map(|_| {
-                        // Constructor splitting should ensure that all intersections we encounter
-                        // are actually inclusions.
-                        assert!(ctor.is_subrange(&pat));
-                        PatStack::default()
-                    }),
-                    _ => None,
-                }
+                let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?;
+                ctor.intersection(cx.tcx, &pat)?;
+                // Constructor splitting should ensure that all intersections we encounter
+                // are actually inclusions.
+                assert!(ctor.is_subrange(&pat));
             } else {
                 // Fallback for non-ranges and ranges that involve
                 // floating-point numbers, which are not conveniently handled
                 // by `IntRange`. For these cases, the constructor may not be a
                 // range so intersection actually devolves into being covered
                 // by the pattern.
-                constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)
-                    .map(|()| PatStack::default())
+                constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)?;
             }
+            Some(Fields::empty())
         }
 
         PatKind::Array { ref prefix, ref slice, ref suffix }
         | PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
             Slice(_) => {
+                // Number of subpatterns for this pattern
                 let pat_len = prefix.len() + suffix.len();
-                if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
-                    if slice_count == 0 || slice.is_some() {
-                        Some(
-                            prefix
-                                .iter()
-                                .chain(
-                                    ctor_wild_subpatterns
-                                        .iter()
-                                        .skip(prefix.len())
-                                        .take(slice_count)
-                                        .chain(suffix.iter()),
-                                )
-                                .collect(),
-                        )
-                    } else {
-                        None
-                    }
-                } else {
-                    None
+                // Number of subpatterns for this constructor
+                let arity = ctor_wild_subpatterns.len();
+
+                if (slice.is_none() && arity != pat_len) || pat_len > arity {
+                    return None;
                 }
+
+                // Replace the prefix and the suffix with the given patterns, leaving wildcards in
+                // the middle if there was a subslice pattern `..`.
+                let prefix = prefix.iter().enumerate();
+                let suffix = suffix.iter().enumerate().map(|(i, p)| (arity - suffix.len() + i, p));
+                Some(ctor_wild_subpatterns.replace_fields_indexed(prefix.chain(suffix)))
             }
             ConstantValue(cv) => {
                 match slice_pat_covered_by_const(
@@ -2494,7 +2637,7 @@
                     suffix,
                     cx.param_env,
                 ) {
-                    Ok(true) => Some(PatStack::default()),
+                    Ok(true) => Some(Fields::empty()),
                     Ok(false) => None,
                     Err(ErrorReported) => None,
                 }
diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs
index 65ff311..7075026 100644
--- a/src/librustc_mir_build/hair/pattern/check_match.rs
+++ b/src/librustc_mir_build/hair/pattern/check_match.rs
@@ -187,9 +187,9 @@
         let matrix = check_arms(&mut cx, &inlined_arms, source);
 
         // Fifth, check if the match is exhaustive.
-        let scrut_ty = self.tables.node_type(scrut.hir_id);
         // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
         // since an empty matrix can occur when there are arms, if those arms all have guards.
+        let scrut_ty = self.tables.expr_ty_adjusted(scrut);
         let is_empty_match = inlined_arms.is_empty();
         check_exhaustive(&mut cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
     }
diff --git a/src/librustc_passes/entry.rs b/src/librustc_passes/entry.rs
index d2f1d11..e0ad0ac 100644
--- a/src/librustc_passes/entry.rs
+++ b/src/librustc_passes/entry.rs
@@ -51,7 +51,7 @@
 fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
     assert_eq!(cnum, LOCAL_CRATE);
 
-    let any_exe = tcx.sess.crate_types.borrow().iter().any(|ty| *ty == CrateType::Executable);
+    let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
     if !any_exe {
         // No need to find a main function.
         return None;
diff --git a/src/librustc_passes/reachable.rs b/src/librustc_passes/reachable.rs
index 7c169d6..cac71b3 100644
--- a/src/librustc_passes/reachable.rs
+++ b/src/librustc_passes/reachable.rs
@@ -376,7 +376,7 @@
     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
 
     let any_library =
-        tcx.sess.crate_types.borrow().iter().any(|ty| {
+        tcx.sess.crate_types().iter().any(|ty| {
             *ty == CrateType::Rlib || *ty == CrateType::Dylib || *ty == CrateType::ProcMacro
         });
     let mut reachable_context = ReachableContext {
diff --git a/src/librustc_passes/weak_lang_items.rs b/src/librustc_passes/weak_lang_items.rs
index 8a58162..96ec236 100644
--- a/src/librustc_passes/weak_lang_items.rs
+++ b/src/librustc_passes/weak_lang_items.rs
@@ -37,7 +37,7 @@
 fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
     // We only need to check for the presence of weak lang items if we're
     // emitting something that's not an rlib.
-    let needs_check = tcx.sess.crate_types.borrow().iter().any(|kind| match *kind {
+    let needs_check = tcx.sess.crate_types().iter().any(|kind| match *kind {
         CrateType::Dylib
         | CrateType::ProcMacro
         | CrateType::Cdylib
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index b474b23..9a63e39 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -90,14 +90,14 @@
     fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool {
         let ty::GenericPredicates { parent: _, predicates } = predicates;
         for (predicate, _span) in predicates {
-            match predicate {
-                ty::Predicate::Trait(poly_predicate, _) => {
+            match predicate.kind() {
+                ty::PredicateKind::Trait(poly_predicate, _) => {
                     let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder();
                     if self.visit_trait(trait_ref) {
                         return true;
                     }
                 }
-                ty::Predicate::Projection(poly_predicate) => {
+                ty::PredicateKind::Projection(poly_predicate) => {
                     let ty::ProjectionPredicate { projection_ty, ty } =
                         *poly_predicate.skip_binder();
                     if ty.visit_with(self) {
@@ -107,13 +107,13 @@
                         return true;
                     }
                 }
-                ty::Predicate::TypeOutlives(poly_predicate) => {
+                ty::PredicateKind::TypeOutlives(poly_predicate) => {
                     let ty::OutlivesPredicate(ty, _region) = *poly_predicate.skip_binder();
                     if ty.visit_with(self) {
                         return true;
                     }
                 }
-                ty::Predicate::RegionOutlives(..) => {}
+                ty::PredicateKind::RegionOutlives(..) => {}
                 _ => bug!("unexpected predicate: {:?}", predicate),
             }
         }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 988ec3d..c32b823 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -126,8 +126,8 @@
     }
 
     crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
-        let def_id = match self.macro_defs.get(&expn_id) {
-            Some(def_id) => *def_id,
+        let def_id = match expn_id.expn_data().macro_def_id {
+            Some(def_id) => def_id,
             None => return self.ast_transform_scopes.get(&expn_id).unwrap_or(&self.graph_root),
         };
         if let Some(id) = self.definitions.as_local_node_id(def_id) {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index bfb7f08..34368a0 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -922,7 +922,6 @@
     dummy_ext_bang: Lrc<SyntaxExtension>,
     dummy_ext_derive: Lrc<SyntaxExtension>,
     non_macro_attrs: [Lrc<SyntaxExtension>; 2],
-    macro_defs: FxHashMap<ExpnId, DefId>,
     local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
     ast_transform_scopes: FxHashMap<ExpnId, Module<'a>>,
     unused_macros: NodeMap<Span>,
@@ -1152,9 +1151,6 @@
         let mut invocation_parent_scopes = FxHashMap::default();
         invocation_parent_scopes.insert(ExpnId::root(), ParentScope::module(graph_root));
 
-        let mut macro_defs = FxHashMap::default();
-        macro_defs.insert(ExpnId::root(), root_def_id);
-
         let features = session.features_untracked();
         let non_macro_attr =
             |mark_used| Lrc::new(SyntaxExtension::non_macro_attr(mark_used, session.edition()));
@@ -1229,7 +1225,6 @@
             invocation_parent_scopes,
             output_macro_rules_scopes: Default::default(),
             helper_attrs: Default::default(),
-            macro_defs,
             local_macro_def_scopes: FxHashMap::default(),
             name_already_seen: FxHashMap::default(),
             potentially_unused_imports: Vec::new(),
@@ -1335,8 +1330,8 @@
 
     fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
         loop {
-            match self.macro_defs.get(&ctxt.outer_expn()) {
-                Some(&def_id) => return def_id,
+            match ctxt.outer_expn().expn_data().macro_def_id {
+                Some(def_id) => return def_id,
                 None => ctxt.remove_mark(),
             };
         }
@@ -1820,7 +1815,7 @@
                 && module.expansion.is_descendant_of(parent.expansion)
             {
                 // The macro is a proc macro derive
-                if let Some(&def_id) = self.macro_defs.get(&module.expansion) {
+                if let Some(def_id) = module.expansion.expn_data().macro_def_id {
                     if let Some(ext) = self.get_macro_by_def_id(def_id) {
                         if !ext.is_builtin && ext.macro_kind() == MacroKind::Derive {
                             if parent.expansion.outer_expn_is_descendant_of(span.ctxt()) {
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 1b6268d..7027c82 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -186,6 +186,7 @@
             call_site,
             self.session.edition(),
             features.into(),
+            None,
         )));
 
         let parent_scope = if let Some(module_id) = parent_module_id {
@@ -290,13 +291,17 @@
         let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?;
 
         let span = invoc.span();
-        invoc_id.set_expn_data(ext.expn_data(parent_scope.expansion, span, fast_print_path(path)));
+        invoc_id.set_expn_data(ext.expn_data(
+            parent_scope.expansion,
+            span,
+            fast_print_path(path),
+            res.opt_def_id(),
+        ));
 
-        if let Res::Def(_, def_id) = res {
+        if let Res::Def(_, _) = res {
             if after_derive {
                 self.session.span_err(span, "macro attributes must be placed before `#[derive]`");
             }
-            self.macro_defs.insert(invoc_id, def_id);
             let normal_module_def_id = self.macro_def_scope(invoc_id).normal_ancestor_id;
             self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
         }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 43fd2b1..3bd68a9 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -87,7 +87,7 @@
     pub fn compilation_output(&self, crate_name: &str) -> PathBuf {
         let sess = &self.tcx.sess;
         // Save-analysis is emitted per whole session, not per each crate type
-        let crate_type = sess.crate_types.borrow()[0];
+        let crate_type = sess.crate_types()[0];
         let outputs = &*self.tcx.output_filenames(LOCAL_CRATE);
 
         if outputs.outputs.contains_key(&OutputType::Metadata) {
@@ -987,8 +987,7 @@
                     error!("Could not create directory {}: {}", root_path.display(), e);
                 }
 
-                let executable =
-                    sess.crate_types.borrow().iter().any(|ct| *ct == CrateType::Executable);
+                let executable = sess.crate_types().iter().any(|ct| *ct == CrateType::Executable);
                 let mut out_name = if executable { String::new() } else { "lib".to_owned() };
                 out_name.push_str(&self.cratename);
                 out_name.push_str(&sess.opts.cg.extra_filename);
diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs
index 5f34a39..5bdd7b6 100644
--- a/src/librustc_session/config.rs
+++ b/src/librustc_session/config.rs
@@ -5,7 +5,7 @@
 
 use crate::lint;
 use crate::search_paths::SearchPath;
-use crate::utils::NativeLibraryKind;
+use crate::utils::NativeLibKind;
 use crate::{early_error, early_warn, Session};
 
 use rustc_data_structures::fx::FxHashSet;
@@ -1452,7 +1452,7 @@
 fn parse_libs(
     matches: &getopts::Matches,
     error_format: ErrorOutputType,
-) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
+) -> Vec<(String, Option<String>, NativeLibKind)> {
     matches
         .opt_strs("l")
         .into_iter()
@@ -1462,13 +1462,11 @@
             let mut parts = s.splitn(2, '=');
             let kind = parts.next().unwrap();
             let (name, kind) = match (parts.next(), kind) {
-                (None, name) => (name, None),
-                (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
-                (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
-                (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
-                (Some(name), "static-nobundle") => {
-                    (name, Some(NativeLibraryKind::NativeStaticNobundle))
-                }
+                (None, name) => (name, NativeLibKind::Unspecified),
+                (Some(name), "dylib") => (name, NativeLibKind::Dylib),
+                (Some(name), "framework") => (name, NativeLibKind::Framework),
+                (Some(name), "static") => (name, NativeLibKind::StaticBundle),
+                (Some(name), "static-nobundle") => (name, NativeLibKind::StaticNoBundle),
                 (_, s) => {
                     early_error(
                         error_format,
@@ -1480,9 +1478,7 @@
                     );
                 }
             };
-            if kind == Some(NativeLibraryKind::NativeStaticNobundle)
-                && !nightly_options::is_nightly_build()
-            {
+            if kind == NativeLibKind::StaticNoBundle && !nightly_options::is_nightly_build() {
                 early_error(
                     error_format,
                     "the library kind 'static-nobundle' is only \
@@ -2003,7 +1999,7 @@
         SymbolManglingVersion,
     };
     use crate::lint;
-    use crate::utils::NativeLibraryKind;
+    use crate::utils::NativeLibKind;
     use rustc_feature::UnstableFeatures;
     use rustc_span::edition::Edition;
     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
@@ -2062,7 +2058,6 @@
     impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
-    impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
     impl_dep_tracking_hash_via_hash!(CrateType);
     impl_dep_tracking_hash_via_hash!(MergeFunctions);
     impl_dep_tracking_hash_via_hash!(PanicStrategy);
@@ -2073,7 +2068,7 @@
     impl_dep_tracking_hash_via_hash!(DebugInfo);
     impl_dep_tracking_hash_via_hash!(UnstableFeatures);
     impl_dep_tracking_hash_via_hash!(OutputTypes);
-    impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
+    impl_dep_tracking_hash_via_hash!(NativeLibKind);
     impl_dep_tracking_hash_via_hash!(Sanitizer);
     impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
     impl_dep_tracking_hash_via_hash!(CFGuard);
@@ -2088,11 +2083,7 @@
     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
-    impl_dep_tracking_hash_for_sortable_vec_of!((
-        String,
-        Option<String>,
-        Option<NativeLibraryKind>
-    ));
+    impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
     impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
     impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
 
diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs
index a8d213a..3b6c21e 100644
--- a/src/librustc_session/options.rs
+++ b/src/librustc_session/options.rs
@@ -3,7 +3,7 @@
 use crate::early_error;
 use crate::lint;
 use crate::search_paths::SearchPath;
-use crate::utils::NativeLibraryKind;
+use crate::utils::NativeLibKind;
 
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
 use rustc_target::spec::{RelocModel, RelroLevel, TargetTriple, TlsModel};
@@ -93,7 +93,7 @@
         describe_lints: bool [UNTRACKED],
         output_types: OutputTypes [TRACKED],
         search_paths: Vec<SearchPath> [UNTRACKED],
-        libs: Vec<(String, Option<String>, Option<NativeLibraryKind>)> [TRACKED],
+        libs: Vec<(String, Option<String>, NativeLibKind)> [TRACKED],
         maybe_sysroot: Option<PathBuf> [UNTRACKED],
 
         target_triple: TargetTriple [TRACKED],
diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs
index 69d3e99..746e353 100644
--- a/src/librustc_session/parse.rs
+++ b/src/librustc_session/parse.rs
@@ -4,7 +4,7 @@
 use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
 use rustc_ast::node_id::NodeId;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::sync::{Lock, Lrc, Once};
+use rustc_data_structures::sync::{Lock, Lrc, OnceCell};
 use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
 use rustc_errors::{error_code, Applicability, DiagnosticBuilder};
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
@@ -130,7 +130,7 @@
     /// operation token that followed it, but that the parser cannot identify without further
     /// analysis.
     pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
-    pub injected_crate_name: Once<Symbol>,
+    pub injected_crate_name: OnceCell<Symbol>,
     pub gated_spans: GatedSpans,
     pub symbol_gallery: SymbolGallery,
     /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
@@ -156,7 +156,7 @@
             source_map,
             buffered_lints: Lock::new(vec![]),
             ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
-            injected_crate_name: Once::new(),
+            injected_crate_name: OnceCell::new(),
             gated_spans: GatedSpans::default(),
             symbol_gallery: SymbolGallery::default(),
             reached_eof: Lock::new(false),
diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs
index 143401d..f2f02cb 100644
--- a/src/librustc_session/session.rs
+++ b/src/librustc_session/session.rs
@@ -13,7 +13,7 @@
 use rustc_data_structures::jobserver::{self, Client};
 use rustc_data_structures::profiling::{duration_to_secs_str, SelfProfiler, SelfProfilerRef};
 use rustc_data_structures::sync::{
-    self, AtomicU64, AtomicUsize, Lock, Lrc, Once, OneThread, Ordering, Ordering::SeqCst,
+    self, AtomicU64, AtomicUsize, Lock, Lrc, OnceCell, OneThread, Ordering, Ordering::SeqCst,
 };
 use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter;
 use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
@@ -77,25 +77,25 @@
     /// (sub)diagnostics that have been set once, but should not be set again,
     /// in order to avoid redundantly verbose output (Issue #24690, #44953).
     pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
-    pub crate_types: Once<Vec<CrateType>>,
+    crate_types: OnceCell<Vec<CrateType>>,
     /// The `crate_disambiguator` is constructed out of all the `-C metadata`
     /// arguments passed to the compiler. Its value together with the crate-name
     /// forms a unique global identifier for the crate. It is used to allow
     /// multiple crates with the same name to coexist. See the
     /// `rustc_codegen_llvm::back::symbol_names` module for more information.
-    pub crate_disambiguator: Once<CrateDisambiguator>,
+    pub crate_disambiguator: OnceCell<CrateDisambiguator>,
 
-    features: Once<rustc_feature::Features>,
+    features: OnceCell<rustc_feature::Features>,
 
     /// The maximum recursion limit for potentially infinitely recursive
     /// operations such as auto-dereference and monomorphization.
-    pub recursion_limit: Once<usize>,
+    pub recursion_limit: OnceCell<usize>,
 
     /// The maximum length of types during monomorphization.
-    pub type_length_limit: Once<usize>,
+    pub type_length_limit: OnceCell<usize>,
 
     /// The maximum blocks a const expression can evaluate.
-    pub const_eval_limit: Once<usize>,
+    pub const_eval_limit: OnceCell<usize>,
 
     incr_comp_session: OneThread<RefCell<IncrCompSession>>,
     /// Used for incremental compilation tests. Will only be populated if
@@ -244,7 +244,27 @@
     }
 
     pub fn local_crate_disambiguator(&self) -> CrateDisambiguator {
-        *self.crate_disambiguator.get()
+        self.crate_disambiguator.get().copied().unwrap()
+    }
+
+    pub fn crate_types(&self) -> &[CrateType] {
+        self.crate_types.get().unwrap().as_slice()
+    }
+
+    pub fn init_crate_types(&self, crate_types: Vec<CrateType>) {
+        self.crate_types.set(crate_types).expect("`crate_types` was initialized twice")
+    }
+
+    pub fn recursion_limit(&self) -> usize {
+        self.recursion_limit.get().copied().unwrap()
+    }
+
+    pub fn type_length_limit(&self) -> usize {
+        self.type_length_limit.get().copied().unwrap()
+    }
+
+    pub fn const_eval_limit(&self) -> usize {
+        self.const_eval_limit.get().copied().unwrap()
     }
 
     pub fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> {
@@ -500,11 +520,14 @@
     /// dependency tracking. Use tcx.features() instead.
     #[inline]
     pub fn features_untracked(&self) -> &rustc_feature::Features {
-        self.features.get()
+        self.features.get().unwrap()
     }
 
     pub fn init_features(&self, features: rustc_feature::Features) {
-        self.features.set(features);
+        match self.features.set(features) {
+            Ok(()) => {}
+            Err(_) => panic!("`features` was initialized twice"),
+        }
     }
 
     /// Calculates the flavor of LTO to use for this compilation.
@@ -1208,12 +1231,12 @@
         local_crate_source_file,
         working_dir,
         one_time_diagnostics: Default::default(),
-        crate_types: Once::new(),
-        crate_disambiguator: Once::new(),
-        features: Once::new(),
-        recursion_limit: Once::new(),
-        type_length_limit: Once::new(),
-        const_eval_limit: Once::new(),
+        crate_types: OnceCell::new(),
+        crate_disambiguator: OnceCell::new(),
+        features: OnceCell::new(),
+        recursion_limit: OnceCell::new(),
+        type_length_limit: OnceCell::new(),
+        const_eval_limit: OnceCell::new(),
         incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
         cgu_reuse_tracker,
         prof,
diff --git a/src/librustc_session/utils.rs b/src/librustc_session/utils.rs
index fda11b6..b97308c 100644
--- a/src/librustc_session/utils.rs
+++ b/src/librustc_session/utils.rs
@@ -11,17 +11,22 @@
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
-pub enum NativeLibraryKind {
-    /// native static library (.a archive)
-    NativeStatic,
-    /// native static library, which doesn't get bundled into .rlibs
-    NativeStaticNobundle,
-    /// macOS-specific
-    NativeFramework,
-    /// Windows dynamic library without import library.
-    NativeRawDylib,
-    /// default way to specify a dynamic library
-    NativeUnknown,
+pub enum NativeLibKind {
+    /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included
+    /// when linking a final binary, but not when archiving an rlib.
+    StaticNoBundle,
+    /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included
+    /// when linking a final binary, but also included when archiving an rlib.
+    StaticBundle,
+    /// Dynamic library (e.g. `libfoo.so` on Linux)
+    /// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC).
+    Dylib,
+    /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library.
+    RawDylib,
+    /// A macOS-specific kind of dynamic libraries.
+    Framework,
+    /// The library kind wasn't specified, `Dylib` is currently used as a default.
+    Unspecified,
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(NativeLibraryKind);
+rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs
index 23c3dcc..c0fb84e 100644
--- a/src/librustc_span/hygiene.rs
+++ b/src/librustc_span/hygiene.rs
@@ -25,6 +25,7 @@
 // because getting it wrong can lead to nested `HygieneData::with` calls that
 // trigger runtime aborts. (Fortunately these are obvious and easy to fix.)
 
+use crate::def_id::{DefId, CRATE_DEF_INDEX};
 use crate::edition::Edition;
 use crate::symbol::{kw, sym, Symbol};
 use crate::GLOBALS;
@@ -155,7 +156,12 @@
 impl HygieneData {
     crate fn new(edition: Edition) -> Self {
         HygieneData {
-            expn_data: vec![Some(ExpnData::default(ExpnKind::Root, DUMMY_SP, edition))],
+            expn_data: vec![Some(ExpnData::default(
+                ExpnKind::Root,
+                DUMMY_SP,
+                edition,
+                Some(DefId::local(CRATE_DEF_INDEX)),
+            ))],
             syntax_context_data: vec![SyntaxContextData {
                 outer_expn: ExpnId::root(),
                 outer_transparency: Transparency::Opaque,
@@ -673,11 +679,19 @@
     pub local_inner_macros: bool,
     /// Edition of the crate in which the macro is defined.
     pub edition: Edition,
+    /// The `DefId` of the macro being invoked,
+    /// if this `ExpnData` corresponds to a macro invocation
+    pub macro_def_id: Option<DefId>,
 }
 
 impl ExpnData {
     /// Constructs expansion data with default properties.
-    pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnData {
+    pub fn default(
+        kind: ExpnKind,
+        call_site: Span,
+        edition: Edition,
+        macro_def_id: Option<DefId>,
+    ) -> ExpnData {
         ExpnData {
             kind,
             parent: ExpnId::root(),
@@ -687,6 +701,7 @@
             allow_internal_unsafe: false,
             local_inner_macros: false,
             edition,
+            macro_def_id,
         }
     }
 
@@ -695,10 +710,11 @@
         call_site: Span,
         edition: Edition,
         allow_internal_unstable: Lrc<[Symbol]>,
+        macro_def_id: Option<DefId>,
     ) -> ExpnData {
         ExpnData {
             allow_internal_unstable: Some(allow_internal_unstable),
-            ..ExpnData::default(kind, call_site, edition)
+            ..ExpnData::default(kind, call_site, edition, macro_def_id)
         }
     }
 
diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs
index 05aa85e..774146a 100644
--- a/src/librustc_target/asm/mod.rs
+++ b/src/librustc_target/asm/mod.rs
@@ -223,19 +223,19 @@
         name: Symbol,
     ) -> Result<Self, &'static str> {
         // FIXME: use direct symbol comparison for register names
-        name.with(|name| {
-            Ok(match arch {
-                InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
-                    Self::X86(X86InlineAsmReg::parse(arch, has_feature, name)?)
-                }
-                InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, name)?),
-                InlineAsmArch::AArch64 => {
-                    Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, name)?)
-                }
-                InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
-                    Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, name)?)
-                }
-            })
+        // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
+        let name = name.as_str();
+        Ok(match arch {
+            InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
+                Self::X86(X86InlineAsmReg::parse(arch, has_feature, &name)?)
+            }
+            InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, &name)?),
+            InlineAsmArch::AArch64 => {
+                Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, &name)?)
+            }
+            InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
+                Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?)
+            }
         })
     }
 
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 8770e03..df17231 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -618,6 +618,7 @@
     ("i686-uwp-windows-msvc", i686_uwp_windows_msvc),
     ("i586-pc-windows-msvc", i586_pc_windows_msvc),
     ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc),
+    ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc),
 
     ("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
     ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
diff --git a/src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs b/src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs
new file mode 100644
index 0000000..ff2e892
--- /dev/null
+++ b/src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs
@@ -0,0 +1,30 @@
+use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::windows_uwp_msvc_base::opts();
+    base.max_atomic_width = Some(64);
+    base.has_elf_tls = true;
+
+    // FIXME(jordanrh): use PanicStrategy::Unwind when SEH is
+    // implemented for windows/arm in LLVM
+    base.panic_strategy = PanicStrategy::Abort;
+
+    Ok(Target {
+        llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        target_os: "windows".to_string(),
+        target_env: "msvc".to_string(),
+        target_vendor: "uwp".to_string(),
+        linker_flavor: LinkerFlavor::Msvc,
+        options: TargetOptions {
+            features: "+vfp3,+neon".to_string(),
+            cpu: "generic".to_string(),
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            ..base
+        },
+    })
+}
diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs
index d26efc0..475a33a 100644
--- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs
+++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs
@@ -1,6 +1,6 @@
 use std::iter;
 
-use super::{crt_objects, LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};
+use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};
 
 pub fn target() -> Result<Target, String> {
     const PRE_LINK_ARGS: &[&str] = &[
@@ -68,8 +68,6 @@
             PRE_LINK_ARGS.iter().cloned().map(String::from).collect(),
         ))
         .collect(),
-        // FIXME: libunwind is certainly not a CRT object, use some other option instead.
-        post_link_objects: crt_objects::all("libunwind.a"),
         override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(String::from).collect()),
         relax_elf_relocations: true,
         ..Default::default()
diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs
index 396965f..484677d 100644
--- a/src/librustc_trait_selection/opaque_types.rs
+++ b/src/librustc_trait_selection/opaque_types.rs
@@ -670,7 +670,7 @@
 // `least_region`. We cannot use `push_outlives_components` because regions in
 // closure signatures are not included in their outlives components. We need to
 // ensure all regions outlive the given bound so that we don't end up with,
-// say, `ReScope` appearing in a return type and causing ICEs when other
+// say, `ReVar` appearing in a return type and causing ICEs when other
 // functions end up with region constraints involving regions from other
 // functions.
 //
@@ -816,7 +816,7 @@
             // The regions that we expect from borrow checking.
             ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
 
-            ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) | ty::ReScope(_) => {
+            ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
                 // All of the regions in the type should either have been
                 // erased by writeback, or mapped back to named regions by
                 // borrow checking.
@@ -835,7 +835,6 @@
                 if let Some(hidden_ty) = self.hidden_ty.take() {
                     unexpected_hidden_region_diagnostic(
                         self.tcx,
-                        None,
                         self.tcx.def_span(self.opaque_type_def_id),
                         hidden_ty,
                         r,
@@ -1168,7 +1167,7 @@
         debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
 
         for predicate in &bounds.predicates {
-            if let ty::Predicate::Projection(projection) = &predicate {
+            if let ty::PredicateKind::Projection(projection) = predicate.kind() {
                 if projection.skip_binder().ty.references_error() {
                     // No point on adding these obligations since there's a type error involved.
                     return ty_var;
@@ -1269,17 +1268,17 @@
     traits::elaborate_predicates(tcx, predicates)
         .filter_map(|obligation| {
             debug!("required_region_bounds(obligation={:?})", obligation);
-            match obligation.predicate {
-                ty::Predicate::Projection(..)
-                | ty::Predicate::Trait(..)
-                | ty::Predicate::Subtype(..)
-                | ty::Predicate::WellFormed(..)
-                | ty::Predicate::ObjectSafe(..)
-                | ty::Predicate::ClosureKind(..)
-                | ty::Predicate::RegionOutlives(..)
-                | ty::Predicate::ConstEvaluatable(..)
-                | ty::Predicate::ConstEquate(..) => None,
-                ty::Predicate::TypeOutlives(predicate) => {
+            match obligation.predicate.kind() {
+                ty::PredicateKind::Projection(..)
+                | ty::PredicateKind::Trait(..)
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::RegionOutlives(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..) => None,
+                ty::PredicateKind::TypeOutlives(predicate) => {
                     // Search for a bound of the form `erased_self_ty
                     // : 'a`, but be wary of something like `for<'a>
                     // erased_self_ty : 'a` (we interpret a
diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs
index e19ddcd..716cbce 100644
--- a/src/librustc_trait_selection/traits/auto_trait.rs
+++ b/src/librustc_trait_selection/traits/auto_trait.rs
@@ -341,7 +341,8 @@
                         already_visited.remove(&pred);
                         self.add_user_pred(
                             &mut user_computed_preds,
-                            ty::Predicate::Trait(pred, hir::Constness::NotConst),
+                            ty::PredicateKind::Trait(pred, hir::Constness::NotConst)
+                                .to_predicate(self.tcx),
                         );
                         predicates.push_back(pred);
                     } else {
@@ -411,8 +412,10 @@
     ) {
         let mut should_add_new = true;
         user_computed_preds.retain(|&old_pred| {
-            if let (&ty::Predicate::Trait(new_trait, _), ty::Predicate::Trait(old_trait, _)) =
-                (&new_pred, old_pred)
+            if let (
+                ty::PredicateKind::Trait(new_trait, _),
+                ty::PredicateKind::Trait(old_trait, _),
+            ) = (new_pred.kind(), old_pred.kind())
             {
                 if new_trait.def_id() == old_trait.def_id() {
                     let new_substs = new_trait.skip_binder().trait_ref.substs;
@@ -630,8 +633,8 @@
             //
             // We check this by calling is_of_param on the relevant types
             // from the various possible predicates
-            match &predicate {
-                &ty::Predicate::Trait(p, _) => {
+            match predicate.kind() {
+                &ty::PredicateKind::Trait(p, _) => {
                     if self.is_param_no_infer(p.skip_binder().trait_ref.substs)
                         && !only_projections
                         && is_new_pred
@@ -640,7 +643,7 @@
                     }
                     predicates.push_back(p);
                 }
-                &ty::Predicate::Projection(p) => {
+                &ty::PredicateKind::Projection(p) => {
                     debug!(
                         "evaluate_nested_obligations: examining projection predicate {:?}",
                         predicate
@@ -765,12 +768,12 @@
                         }
                     }
                 }
-                &ty::Predicate::RegionOutlives(ref binder) => {
+                ty::PredicateKind::RegionOutlives(ref binder) => {
                     if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() {
                         return false;
                     }
                 }
-                &ty::Predicate::TypeOutlives(ref binder) => {
+                ty::PredicateKind::TypeOutlives(ref binder) => {
                     match (
                         binder.no_bound_vars(),
                         binder.map_bound_ref(|pred| pred.0).no_bound_vars(),
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index 139b860..b1c6815 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -252,8 +252,8 @@
                     .emit();
                     return;
                 }
-                match obligation.predicate {
-                    ty::Predicate::Trait(ref trait_predicate, _) => {
+                match obligation.predicate.kind() {
+                    ty::PredicateKind::Trait(ref trait_predicate, _) => {
                         let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
 
                         if self.tcx.sess.has_errors() && trait_predicate.references_error() {
@@ -308,7 +308,7 @@
                             "{}",
                             message.unwrap_or_else(|| format!(
                                 "the trait bound `{}` is not satisfied{}",
-                                trait_ref.without_const().to_predicate(),
+                                trait_ref.without_const().to_predicate(tcx),
                                 post_message,
                             ))
                         );
@@ -468,10 +468,11 @@
                                 trait_pred
                             });
                             let unit_obligation = Obligation {
-                                predicate: ty::Predicate::Trait(
+                                predicate: ty::PredicateKind::Trait(
                                     predicate,
                                     hir::Constness::NotConst,
-                                ),
+                                )
+                                .to_predicate(self.tcx),
                                 ..obligation.clone()
                             };
                             if self.predicate_may_hold(&unit_obligation) {
@@ -489,14 +490,14 @@
                         err
                     }
 
-                    ty::Predicate::Subtype(ref predicate) => {
+                    ty::PredicateKind::Subtype(ref predicate) => {
                         // Errors for Subtype predicates show up as
                         // `FulfillmentErrorCode::CodeSubtypeError`,
                         // not selection error.
                         span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
                     }
 
-                    ty::Predicate::RegionOutlives(ref predicate) => {
+                    ty::PredicateKind::RegionOutlives(ref predicate) => {
                         let predicate = self.resolve_vars_if_possible(predicate);
                         let err = self
                             .region_outlives_predicate(&obligation.cause, &predicate)
@@ -512,7 +513,7 @@
                         )
                     }
 
-                    ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
+                    ty::PredicateKind::Projection(..) | ty::PredicateKind::TypeOutlives(..) => {
                         let predicate = self.resolve_vars_if_possible(&obligation.predicate);
                         struct_span_err!(
                             self.tcx.sess,
@@ -523,12 +524,12 @@
                         )
                     }
 
-                    ty::Predicate::ObjectSafe(trait_def_id) => {
+                    &ty::PredicateKind::ObjectSafe(trait_def_id) => {
                         let violations = self.tcx.object_safety_violations(trait_def_id);
                         report_object_safety_error(self.tcx, span, trait_def_id, violations)
                     }
 
-                    ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
+                    &ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                         let found_kind = self.closure_kind(closure_substs).unwrap();
                         let closure_span =
                             self.tcx.sess.source_map().guess_head_span(
@@ -587,7 +588,7 @@
                         return;
                     }
 
-                    ty::Predicate::WellFormed(ty) => {
+                    ty::PredicateKind::WellFormed(ty) => {
                         if !self.tcx.sess.opts.debugging_opts.chalk {
                             // WF predicates cannot themselves make
                             // errors. They can only block due to
@@ -605,7 +606,7 @@
                         }
                     }
 
-                    ty::Predicate::ConstEvaluatable(..) => {
+                    ty::PredicateKind::ConstEvaluatable(..) => {
                         // Errors for `ConstEvaluatable` predicates show up as
                         // `SelectionError::ConstEvalFailure`,
                         // not `Unimplemented`.
@@ -616,7 +617,7 @@
                         )
                     }
 
-                    ty::Predicate::ConstEquate(..) => {
+                    ty::PredicateKind::ConstEquate(..) => {
                         // Errors for `ConstEquate` predicates show up as
                         // `SelectionError::ConstEvalFailure`,
                         // not `Unimplemented`.
@@ -999,12 +1000,15 @@
         trait_ref: &ty::PolyTraitRef<'tcx>,
     );
 
-    fn mk_obligation_for_def_id(
+    /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
+    /// `trait_ref`.
+    ///
+    /// For this to work, `new_self_ty` must have no escaping bound variables.
+    fn mk_trait_obligation_with_new_self_ty(
         &self,
-        def_id: DefId,
-        output_ty: Ty<'tcx>,
-        cause: ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
+        trait_ref: &ty::PolyTraitRef<'tcx>,
+        new_self_ty: Ty<'tcx>,
     ) -> PredicateObligation<'tcx>;
 
     fn maybe_report_ambiguity(
@@ -1021,13 +1025,13 @@
 
     fn note_obligation_cause(
         &self,
-        err: &mut DiagnosticBuilder<'_>,
+        err: &mut DiagnosticBuilder<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     );
 
     fn suggest_unsized_bound_if_applicable(
         &self,
-        err: &mut DiagnosticBuilder<'_>,
+        err: &mut DiagnosticBuilder<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     );
 
@@ -1046,8 +1050,8 @@
             return true;
         }
 
-        let (cond, error) = match (cond, error) {
-            (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error),
+        let (cond, error) = match (cond.kind(), error.kind()) {
+            (ty::PredicateKind::Trait(..), ty::PredicateKind::Trait(error, _)) => (cond, error),
             _ => {
                 // FIXME: make this work in other cases too.
                 return false;
@@ -1055,7 +1059,7 @@
         };
 
         for obligation in super::elaborate_predicates(self.tcx, std::iter::once(*cond)) {
-            if let ty::Predicate::Trait(implication, _) = obligation.predicate {
+            if let ty::PredicateKind::Trait(implication, _) = obligation.predicate.kind() {
                 let error = error.to_poly_trait_ref();
                 let implication = implication.to_poly_trait_ref();
                 // FIXME: I'm just not taking associated types at all here.
@@ -1135,7 +1139,7 @@
             //
             // this can fail if the problem was higher-ranked, in which
             // cause I have no idea for a good error message.
-            if let ty::Predicate::Projection(ref data) = predicate {
+            if let ty::PredicateKind::Projection(ref data) = predicate.kind() {
                 let mut selcx = SelectionContext::new(self);
                 let (data, _) = self.replace_bound_vars_with_fresh_vars(
                     obligation.cause.span,
@@ -1379,16 +1383,24 @@
         }
     }
 
-    fn mk_obligation_for_def_id(
+    fn mk_trait_obligation_with_new_self_ty(
         &self,
-        def_id: DefId,
-        output_ty: Ty<'tcx>,
-        cause: ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
+        trait_ref: &ty::PolyTraitRef<'tcx>,
+        new_self_ty: Ty<'tcx>,
     ) -> PredicateObligation<'tcx> {
-        let new_trait_ref =
-            ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) };
-        Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate())
+        assert!(!new_self_ty.has_escaping_bound_vars());
+
+        let trait_ref = trait_ref.map_bound_ref(|tr| ty::TraitRef {
+            substs: self.tcx.mk_substs_trait(new_self_ty, &tr.substs[1..]),
+            ..*tr
+        });
+
+        Obligation::new(
+            ObligationCause::dummy(),
+            param_env,
+            trait_ref.without_const().to_predicate(self.tcx),
+        )
     }
 
     fn maybe_report_ambiguity(
@@ -1415,8 +1427,8 @@
             return;
         }
 
-        let mut err = match predicate {
-            ty::Predicate::Trait(ref data, _) => {
+        let mut err = match predicate.kind() {
+            ty::PredicateKind::Trait(ref data, _) => {
                 let trait_ref = data.to_poly_trait_ref();
                 let self_ty = trait_ref.self_ty();
                 debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref);
@@ -1515,7 +1527,7 @@
                 err
             }
 
-            ty::Predicate::WellFormed(ty) => {
+            ty::PredicateKind::WellFormed(ty) => {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
                 if ty.references_error() || self.tcx.sess.has_errors() {
@@ -1524,7 +1536,7 @@
                 self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
             }
 
-            ty::Predicate::Subtype(ref data) => {
+            ty::PredicateKind::Subtype(ref data) => {
                 if data.references_error() || self.tcx.sess.has_errors() {
                     // no need to overload user in such cases
                     return;
@@ -1534,7 +1546,7 @@
                 assert!(a.is_ty_var() && b.is_ty_var());
                 self.need_type_info_err(body_id, span, a, ErrorCode::E0282)
             }
-            ty::Predicate::Projection(ref data) => {
+            ty::PredicateKind::Projection(ref data) => {
                 let trait_ref = data.to_poly_trait_ref(self.tcx);
                 let self_ty = trait_ref.self_ty();
                 let ty = data.skip_binder().ty;
@@ -1627,7 +1639,7 @@
             let obligation = Obligation::new(
                 ObligationCause::dummy(),
                 param_env,
-                cleaned_pred.without_const().to_predicate(),
+                cleaned_pred.without_const().to_predicate(selcx.tcx()),
             );
 
             self.predicate_may_hold(&obligation)
@@ -1636,7 +1648,7 @@
 
     fn note_obligation_cause(
         &self,
-        err: &mut DiagnosticBuilder<'_>,
+        err: &mut DiagnosticBuilder<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     ) {
         // First, attempt to add note to this error with an async-await-specific
@@ -1654,13 +1666,13 @@
 
     fn suggest_unsized_bound_if_applicable(
         &self,
-        err: &mut DiagnosticBuilder<'_>,
+        err: &mut DiagnosticBuilder<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     ) {
         if let (
-            ty::Predicate::Trait(pred, _),
+            ty::PredicateKind::Trait(pred, _),
             ObligationCauseCode::BindingObligation(item_def_id, span),
-        ) = (&obligation.predicate, &obligation.cause.code)
+        ) = (obligation.predicate.kind(), &obligation.cause.code)
         {
             if let (Some(generics), true) = (
                 self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()),
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index b8771d5..5c85855 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -38,14 +38,14 @@
     fn suggest_restricting_param_bound(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::PolyTraitRef<'_>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         body_id: hir::HirId,
     );
 
     fn suggest_borrow_on_unsized_slice(
         &self,
         code: &ObligationCauseCode<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
     );
 
     fn get_closure_name(
@@ -66,7 +66,7 @@
     fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
         points_at_arg: bool,
         has_custom_message: bool,
@@ -75,14 +75,14 @@
     fn suggest_remove_reference(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
     );
 
     fn suggest_change_mut(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
         points_at_arg: bool,
     );
@@ -90,7 +90,7 @@
     fn suggest_semicolon_removal(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         span: Span,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
     );
@@ -99,7 +99,7 @@
 
     fn suggest_impl_trait(
         &self,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         span: Span,
         obligation: &PredicateObligation<'tcx>,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
@@ -107,7 +107,7 @@
 
     fn point_at_returns_when_relevant(
         &self,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         obligation: &PredicateObligation<'tcx>,
     );
 
@@ -138,11 +138,11 @@
         err: &mut DiagnosticBuilder<'_>,
         interior_or_upvar_span: GeneratorInteriorOrUpvar,
         interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
-        inner_generator_body: Option<&hir::Body<'_>>,
+        inner_generator_body: Option<&hir::Body<'tcx>>,
         outer_generator: Option<DefId>,
-        trait_ref: ty::TraitRef<'_>,
+        trait_ref: ty::TraitRef<'tcx>,
         target_ty: Ty<'tcx>,
-        tables: &ty::TypeckTables<'_>,
+        tables: &ty::TypeckTables<'tcx>,
         obligation: &PredicateObligation<'tcx>,
         next_code: Option<&ObligationCauseCode<'tcx>>,
     );
@@ -183,12 +183,13 @@
 /// it can also be an `impl Trait` param that needs to be decomposed to a type
 /// param for cleaner code.
 fn suggest_restriction(
-    generics: &hir::Generics<'_>,
+    tcx: TyCtxt<'tcx>,
+    generics: &hir::Generics<'tcx>,
     msg: &str,
     err: &mut DiagnosticBuilder<'_>,
     fn_sig: Option<&hir::FnSig<'_>>,
     projection: Option<&ty::ProjectionTy<'_>>,
-    trait_ref: ty::PolyTraitRef<'_>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
     super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
 ) {
     // When we are dealing with a trait, `super_traits` will be `Some`:
@@ -243,7 +244,7 @@
 
         // FIXME: modify the `trait_ref` instead of string shenanigans.
         // Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`.
-        let pred = trait_ref.without_const().to_predicate().to_string();
+        let pred = trait_ref.without_const().to_predicate(tcx).to_string();
         let pred = pred.replace(&impl_trait_str, &type_param_name);
         let mut sugg = vec![
             match generics
@@ -285,9 +286,10 @@
     } else {
         // Trivial case: `T` needs an extra bound: `T: Bound`.
         let (sp, suggestion) = match super_traits {
-            None => {
-                predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string())
-            }
+            None => predicate_constraint(
+                generics,
+                trait_ref.without_const().to_predicate(tcx).to_string(),
+            ),
             Some((ident, bounds)) => match bounds {
                 [.., bound] => (
                     bound.span().shrink_to_hi(),
@@ -313,7 +315,7 @@
     fn suggest_restricting_param_bound(
         &self,
         mut err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::PolyTraitRef<'_>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         body_id: hir::HirId,
     ) {
         let self_ty = trait_ref.self_ty();
@@ -336,6 +338,7 @@
                     assert!(param_ty);
                     // Restricting `Self` for a single method.
                     suggest_restriction(
+                        self.tcx,
                         &generics,
                         "`Self`",
                         err,
@@ -355,7 +358,7 @@
                     assert!(param_ty);
                     // Restricting `Self` for a single method.
                     suggest_restriction(
-                        &generics, "`Self`", err, None, projection, trait_ref, None,
+                        self.tcx, &generics, "`Self`", err, None, projection, trait_ref, None,
                     );
                     return;
                 }
@@ -375,6 +378,7 @@
                 }) if projection.is_some() => {
                     // Missing restriction on associated type of type parameter (unmet projection).
                     suggest_restriction(
+                        self.tcx,
                         &generics,
                         "the associated type",
                         err,
@@ -393,6 +397,7 @@
                 }) if projection.is_some() => {
                     // Missing restriction on associated type of type parameter (unmet projection).
                     suggest_restriction(
+                        self.tcx,
                         &generics,
                         "the associated type",
                         err,
@@ -450,7 +455,7 @@
     fn suggest_borrow_on_unsized_slice(
         &self,
         code: &ObligationCauseCode<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
     ) {
         if let &ObligationCauseCode::VariableType(hir_id) = code {
             let parent_node = self.tcx.hir().get_parent_node(hir_id);
@@ -527,14 +532,17 @@
         };
         let msg = format!("use parentheses to call the {}", callable);
 
-        let obligation = self.mk_obligation_for_def_id(
-            trait_ref.def_id(),
-            output_ty.skip_binder(),
-            obligation.cause.clone(),
-            obligation.param_env,
-        );
+        // `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound
+        // variables, so bail out if we have any.
+        let output_ty = match output_ty.no_bound_vars() {
+            Some(ty) => ty,
+            None => return,
+        };
 
-        match self.evaluate_obligation(&obligation) {
+        let new_obligation =
+            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_ref, output_ty);
+
+        match self.evaluate_obligation(&new_obligation) {
             Ok(
                 EvaluationResult::EvaluatedToOk
                 | EvaluationResult::EvaluatedToOkModuloRegions
@@ -601,7 +609,7 @@
     fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
         points_at_arg: bool,
         has_custom_message: bool,
@@ -624,8 +632,9 @@
             let new_obligation = Obligation::new(
                 ObligationCause::dummy(),
                 param_env,
-                new_trait_ref.without_const().to_predicate(),
+                new_trait_ref.without_const().to_predicate(self.tcx),
             );
+
             if self.predicate_must_hold_modulo_regions(&new_obligation) {
                 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
                     // We have a very specific type of error, where just borrowing this argument
@@ -633,6 +642,7 @@
                     // original type obligation, not the last one that failed, which is arbitrary.
                     // Because of this, we modify the error to refer to the original obligation and
                     // return early in the caller.
+
                     let msg = format!(
                         "the trait bound `{}: {}` is not satisfied",
                         found,
@@ -655,12 +665,23 @@
                             obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
                         ),
                     );
-                    err.span_suggestion(
-                        span,
-                        "consider borrowing here",
-                        format!("&{}", snippet),
-                        Applicability::MaybeIncorrect,
-                    );
+
+                    // This if is to prevent a special edge-case
+                    if !span.from_expansion() {
+                        // We don't want a borrowing suggestion on the fields in structs,
+                        // ```
+                        // struct Foo {
+                        //  the_foos: Vec<Foo>
+                        // }
+                        // ```
+
+                        err.span_suggestion(
+                            span,
+                            "consider borrowing here",
+                            format!("&{}", snippet),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                     return true;
                 }
             }
@@ -673,10 +694,9 @@
     fn suggest_remove_reference(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
     ) {
-        let trait_ref = trait_ref.skip_binder();
         let span = obligation.cause.span;
 
         if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -687,17 +707,16 @@
                 return;
             }
 
-            let mut trait_type = trait_ref.self_ty();
+            let mut suggested_ty = trait_ref.self_ty();
 
             for refs_remaining in 0..refs_number {
-                if let ty::Ref(_, t_type, _) = trait_type.kind {
-                    trait_type = t_type;
+                if let ty::Ref(_, inner_ty, _) = suggested_ty.kind {
+                    suggested_ty = inner_ty;
 
-                    let new_obligation = self.mk_obligation_for_def_id(
-                        trait_ref.def_id,
-                        trait_type,
-                        ObligationCause::dummy(),
+                    let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                         obligation.param_env,
+                        trait_ref,
+                        suggested_ty,
                     );
 
                     if self.predicate_may_hold(&new_obligation) {
@@ -735,7 +754,7 @@
     fn suggest_change_mut(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
         points_at_arg: bool,
     ) {
@@ -764,20 +783,20 @@
                     return;
                 }
 
-                let trait_type = match mutability {
+                let suggested_ty = match mutability {
                     hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
                     hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
                 };
 
-                let new_obligation = self.mk_obligation_for_def_id(
-                    trait_ref.skip_binder().def_id,
-                    trait_type,
-                    ObligationCause::dummy(),
+                let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
+                    &trait_ref,
+                    suggested_ty,
                 );
-
-                if self.evaluate_obligation_no_overflow(&new_obligation).must_apply_modulo_regions()
-                {
+                let suggested_ty_would_satisfy_obligation = self
+                    .evaluate_obligation_no_overflow(&new_obligation)
+                    .must_apply_modulo_regions();
+                if suggested_ty_would_satisfy_obligation {
                     let sp = self
                         .tcx
                         .sess
@@ -794,7 +813,7 @@
                         err.note(&format!(
                             "`{}` is implemented for `{:?}`, but not for `{:?}`",
                             trait_ref.print_only_trait_path(),
-                            trait_type,
+                            suggested_ty,
                             trait_ref.skip_binder().self_ty(),
                         ));
                     }
@@ -806,7 +825,7 @@
     fn suggest_semicolon_removal(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         span: Span,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
     ) {
@@ -852,7 +871,7 @@
     /// emitted.
     fn suggest_impl_trait(
         &self,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         span: Span,
         obligation: &PredicateObligation<'tcx>,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
@@ -1048,7 +1067,7 @@
 
     fn point_at_returns_when_relevant(
         &self,
-        err: &mut DiagnosticBuilder<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
         obligation: &PredicateObligation<'tcx>,
     ) {
         match obligation.cause.code.peel_derives() {
@@ -1237,8 +1256,8 @@
         // the type. The last generator (`outer_generator` below) has information about where the
         // bound was introduced. At least one generator should be present for this diagnostic to be
         // modified.
-        let (mut trait_ref, mut target_ty) = match obligation.predicate {
-            ty::Predicate::Trait(p, _) => {
+        let (mut trait_ref, mut target_ty) = match obligation.predicate.kind() {
+            ty::PredicateKind::Trait(p, _) => {
                 (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty()))
             }
             _ => (None, None),
@@ -1430,11 +1449,11 @@
         err: &mut DiagnosticBuilder<'_>,
         interior_or_upvar_span: GeneratorInteriorOrUpvar,
         interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
-        inner_generator_body: Option<&hir::Body<'_>>,
+        inner_generator_body: Option<&hir::Body<'tcx>>,
         outer_generator: Option<DefId>,
-        trait_ref: ty::TraitRef<'_>,
+        trait_ref: ty::TraitRef<'tcx>,
         target_ty: Ty<'tcx>,
-        tables: &ty::TypeckTables<'_>,
+        tables: &ty::TypeckTables<'tcx>,
         obligation: &PredicateObligation<'tcx>,
         next_code: Option<&ObligationCauseCode<'tcx>>,
     ) {
@@ -1788,7 +1807,7 @@
                 err.note(&format!("required because it appears within the type `{}`", ty));
                 obligated_types.push(ty);
 
-                let parent_predicate = parent_trait_ref.without_const().to_predicate();
+                let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
                 if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
                     self.note_obligation_cause_code(
                         err,
@@ -1805,7 +1824,7 @@
                     parent_trait_ref.print_only_trait_path(),
                     parent_trait_ref.skip_binder().self_ty()
                 ));
-                let parent_predicate = parent_trait_ref.without_const().to_predicate();
+                let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
                 self.note_obligation_cause_code(
                     err,
                     &parent_predicate,
@@ -1815,7 +1834,7 @@
             }
             ObligationCauseCode::DerivedObligation(ref data) => {
                 let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
-                let parent_predicate = parent_trait_ref.without_const().to_predicate();
+                let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
                 self.note_obligation_cause_code(
                     err,
                     &parent_predicate,
@@ -1857,7 +1876,7 @@
     }
 
     fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
-        let current_limit = self.tcx.sess.recursion_limit.get();
+        let current_limit = self.tcx.sess.recursion_limit();
         let suggested_limit = current_limit * 2;
         err.help(&format!(
             "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
@@ -1873,7 +1892,7 @@
         span: Span,
     ) {
         debug!(
-            "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}",
+            "suggest_await_before_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}",
             obligation,
             span,
             trait_ref,
@@ -1928,16 +1947,15 @@
                 );
 
                 debug!(
-                    "suggest_await_befor_try: normalized_projection_type {:?}",
+                    "suggest_await_before_try: normalized_projection_type {:?}",
                     self.resolve_vars_if_possible(&normalized_ty)
                 );
-                let try_obligation = self.mk_obligation_for_def_id(
-                    trait_ref.def_id(),
-                    normalized_ty,
-                    obligation.cause.clone(),
+                let try_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
+                    trait_ref,
+                    normalized_ty,
                 );
-                debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation);
+                debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
                 if self.predicate_may_hold(&try_obligation) && impls_future {
                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
                         if snippet.ends_with('?') {
@@ -2061,7 +2079,7 @@
 }
 
 fn suggest_trait_object_return_type_alternatives(
-    err: &mut DiagnosticBuilder<'tcx>,
+    err: &mut DiagnosticBuilder<'_>,
     ret_ty: Span,
     trait_obj: &str,
     is_object_safe: bool,
diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs
index 98f6ac0..e44163f 100644
--- a/src/librustc_trait_selection/traits/fulfill.rs
+++ b/src/librustc_trait_selection/traits/fulfill.rs
@@ -83,7 +83,7 @@
 
 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(PendingPredicateObligation<'_>, 136);
+static_assert_size!(PendingPredicateObligation<'_>, 112);
 
 impl<'a, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
@@ -322,8 +322,8 @@
 
         let infcx = self.selcx.infcx();
 
-        match obligation.predicate {
-            ty::Predicate::Trait(ref data, _) => {
+        match obligation.predicate.kind() {
+            ty::PredicateKind::Trait(ref data, _) => {
                 let trait_obligation = obligation.with(*data);
 
                 if data.is_global() {
@@ -378,14 +378,14 @@
                 }
             }
 
-            ty::Predicate::RegionOutlives(ref binder) => {
+            ty::PredicateKind::RegionOutlives(ref binder) => {
                 match infcx.region_outlives_predicate(&obligation.cause, binder) {
                     Ok(()) => ProcessResult::Changed(vec![]),
                     Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
                 }
             }
 
-            ty::Predicate::TypeOutlives(ref binder) => {
+            ty::PredicateKind::TypeOutlives(ref binder) => {
                 // Check if there are higher-ranked vars.
                 match binder.no_bound_vars() {
                     // If there are, inspect the underlying type further.
@@ -429,7 +429,7 @@
                 }
             }
 
-            ty::Predicate::Projection(ref data) => {
+            ty::PredicateKind::Projection(ref data) => {
                 let project_obligation = obligation.with(*data);
                 match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
                     Ok(None) => {
@@ -443,7 +443,7 @@
                 }
             }
 
-            ty::Predicate::ObjectSafe(trait_def_id) => {
+            &ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 if !self.selcx.tcx().is_object_safe(trait_def_id) {
                     ProcessResult::Error(CodeSelectionError(Unimplemented))
                 } else {
@@ -451,7 +451,7 @@
                 }
             }
 
-            ty::Predicate::ClosureKind(_, closure_substs, kind) => {
+            &ty::PredicateKind::ClosureKind(_, closure_substs, kind) => {
                 match self.selcx.infcx().closure_kind(closure_substs) {
                     Some(closure_kind) => {
                         if closure_kind.extends(kind) {
@@ -464,7 +464,7 @@
                 }
             }
 
-            ty::Predicate::WellFormed(ty) => {
+            &ty::PredicateKind::WellFormed(ty) => {
                 match wf::obligations(
                     self.selcx.infcx(),
                     obligation.param_env,
@@ -481,7 +481,7 @@
                 }
             }
 
-            ty::Predicate::Subtype(ref subtype) => {
+            ty::PredicateKind::Subtype(subtype) => {
                 match self.selcx.infcx().subtype_predicate(
                     &obligation.cause,
                     obligation.param_env,
@@ -510,7 +510,7 @@
                 }
             }
 
-            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+            &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
                 match self.selcx.infcx().const_eval_resolve(
                     obligation.param_env,
                     def_id,
@@ -523,7 +523,7 @@
                 }
             }
 
-            ty::Predicate::ConstEquate(c1, c2) => {
+            ty::PredicateKind::ConstEquate(c1, c2) => {
                 debug!("equating consts: c1={:?} c2={:?}", c1, c2);
 
                 let stalled_on = &mut pending_obligation.stalled_on;
diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs
index 9592f93..d8e99dc 100644
--- a/src/librustc_trait_selection/traits/mod.rs
+++ b/src/librustc_trait_selection/traits/mod.rs
@@ -28,7 +28,6 @@
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::middle::region;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{
@@ -143,7 +142,7 @@
         param_env,
         cause: ObligationCause::misc(span, hir::CRATE_HIR_ID),
         recursion_depth: 0,
-        predicate: trait_ref.without_const().to_predicate(),
+        predicate: trait_ref.without_const().to_predicate(infcx.tcx),
     };
 
     let result = infcx.predicate_must_hold_modulo_regions(&obligation);
@@ -237,15 +236,12 @@
 
         debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
 
-        let region_scope_tree = region::ScopeTree::default();
-
         // We can use the `elaborated_env` here; the region code only
         // cares about declarations like `'a: 'b`.
         let outlives_env = OutlivesEnvironment::new(elaborated_env);
 
         infcx.resolve_regions_and_report_errors(
             region_context,
-            &region_scope_tree,
             &outlives_env,
             RegionckMode::default(),
         );
@@ -333,8 +329,8 @@
     // This works fairly well because trait matching  does not actually care about param-env
     // TypeOutlives predicates - these are normally used by regionck.
     let outlives_predicates: Vec<_> = predicates
-        .drain_filter(|predicate| match predicate {
-            ty::Predicate::TypeOutlives(..) => true,
+        .drain_filter(|predicate| match predicate.kind() {
+            ty::PredicateKind::TypeOutlives(..) => true,
             _ => false,
         })
         .collect();
@@ -557,7 +553,7 @@
         cause: ObligationCause::dummy(),
         param_env,
         recursion_depth: 0,
-        predicate: trait_ref.without_const().to_predicate(),
+        predicate: trait_ref.without_const().to_predicate(tcx),
     };
     tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
 }
diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs
index 1bfcacd..b2d684e 100644
--- a/src/librustc_trait_selection/traits/object_safety.rs
+++ b/src/librustc_trait_selection/traits/object_safety.rs
@@ -245,8 +245,8 @@
         .iter()
         .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
         .filter_map(|(predicate, &sp)| {
-            match predicate {
-                ty::Predicate::Trait(ref data, _) => {
+            match predicate.kind() {
+                ty::PredicateKind::Trait(ref data, _) => {
                     // In the case of a trait predicate, we can skip the "self" type.
                     if data.skip_binder().trait_ref.substs[1..].iter().any(has_self_ty) {
                         Some(sp)
@@ -254,7 +254,7 @@
                         None
                     }
                 }
-                ty::Predicate::Projection(ref data) => {
+                ty::PredicateKind::Projection(ref data) => {
                     // And similarly for projections. This should be redundant with
                     // the previous check because any projection should have a
                     // matching `Trait` predicate with the same inputs, but we do
@@ -276,14 +276,14 @@
                         None
                     }
                 }
-                ty::Predicate::WellFormed(..)
-                | ty::Predicate::ObjectSafe(..)
-                | ty::Predicate::TypeOutlives(..)
-                | ty::Predicate::RegionOutlives(..)
-                | ty::Predicate::ClosureKind(..)
-                | ty::Predicate::Subtype(..)
-                | ty::Predicate::ConstEvaluatable(..)
-                | ty::Predicate::ConstEquate(..) => None,
+                ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::TypeOutlives(..)
+                | ty::PredicateKind::RegionOutlives(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..) => None,
             }
         })
         .collect()
@@ -304,19 +304,22 @@
     // Search for a predicate like `Self : Sized` amongst the trait bounds.
     let predicates = tcx.predicates_of(def_id);
     let predicates = predicates.instantiate_identity(tcx).predicates;
-    elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| match obligation.predicate {
-        ty::Predicate::Trait(ref trait_pred, _) => {
-            trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0)
+    elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| {
+        match obligation.predicate.kind() {
+            ty::PredicateKind::Trait(ref trait_pred, _) => {
+                trait_pred.def_id() == sized_def_id
+                    && trait_pred.skip_binder().self_ty().is_param(0)
+            }
+            ty::PredicateKind::Projection(..)
+            | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::RegionOutlives(..)
+            | ty::PredicateKind::WellFormed(..)
+            | ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::TypeOutlives(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..) => false,
         }
-        ty::Predicate::Projection(..)
-        | ty::Predicate::Subtype(..)
-        | ty::Predicate::RegionOutlives(..)
-        | ty::Predicate::WellFormed(..)
-        | ty::Predicate::ObjectSafe(..)
-        | ty::Predicate::ClosureKind(..)
-        | ty::Predicate::TypeOutlives(..)
-        | ty::Predicate::ConstEvaluatable(..)
-        | ty::Predicate::ConstEquate(..) => false,
     })
 }
 
@@ -636,7 +639,7 @@
             substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
         }
         .without_const()
-        .to_predicate();
+        .to_predicate(tcx);
 
         // U: Trait<Arg1, ..., ArgN>
         let trait_predicate = {
@@ -649,7 +652,7 @@
                     }
                 });
 
-            ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate()
+            ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate(tcx)
         };
 
         let caller_bounds: Vec<Predicate<'tcx>> = param_env
@@ -672,7 +675,7 @@
             substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
         }
         .without_const()
-        .to_predicate();
+        .to_predicate(tcx);
 
         Obligation::new(ObligationCause::dummy(), param_env, predicate)
     };
diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index f102f34..914485f 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -332,7 +332,7 @@
                     Reveal::UserFacing => ty,
 
                     Reveal::All => {
-                        let recursion_limit = *self.tcx().sess.recursion_limit.get();
+                        let recursion_limit = self.tcx().sess.recursion_limit();
                         if self.depth >= recursion_limit {
                             let obligation = Obligation::with_depth(
                                 self.cause.clone(),
@@ -436,7 +436,7 @@
         });
         let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
         let obligation =
-            Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate());
+            Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate(tcx));
         obligations.push(obligation);
         ty_var
     })
@@ -520,7 +520,7 @@
             );
 
             // But for now, let's classify this as an overflow:
-            let recursion_limit = *selcx.tcx().sess.recursion_limit.get();
+            let recursion_limit = selcx.tcx().sess.recursion_limit();
             let obligation =
                 Obligation::with_depth(cause, recursion_limit, param_env, projection_ty);
             selcx.infcx().report_overflow_error(&obligation, false);
@@ -665,7 +665,7 @@
     let mut obligations: Vec<_> = result
         .obligations
         .iter()
-        .filter(|obligation| match obligation.predicate {
+        .filter(|obligation| match obligation.predicate.kind() {
             // We found a `T: Foo<X = U>` predicate, let's check
             // if `U` references any unresolved type
             // variables. In principle, we only care if this
@@ -675,7 +675,9 @@
             // indirect obligations (e.g., we project to `?0`,
             // but we have `T: Foo<X = ?1>` and `?1: Bar<X =
             // ?0>`).
-            ty::Predicate::Projection(ref data) => infcx.unresolved_type_vars(&data.ty()).is_some(),
+            ty::PredicateKind::Projection(ref data) => {
+                infcx.unresolved_type_vars(&data.ty()).is_some()
+            }
 
             // We are only interested in `T: Foo<X = U>` predicates, whre
             // `U` references one of `unresolved_type_vars`. =)
@@ -724,7 +726,7 @@
         cause,
         recursion_depth: depth,
         param_env,
-        predicate: trait_ref.without_const().to_predicate(),
+        predicate: trait_ref.without_const().to_predicate(infcx.tcx),
     }
 }
 
@@ -759,7 +761,7 @@
         cause,
         recursion_depth: depth,
         param_env,
-        predicate: trait_ref.without_const().to_predicate(),
+        predicate: trait_ref.without_const().to_predicate(selcx.tcx()),
     };
     let tcx = selcx.infcx().tcx;
     let def_id = projection_ty.item_def_id;
@@ -812,7 +814,7 @@
 ) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> {
     debug!("project(obligation={:?})", obligation);
 
-    let recursion_limit = *selcx.tcx().sess.recursion_limit.get();
+    let recursion_limit = selcx.tcx().sess.recursion_limit();
     if obligation.recursion_depth >= recursion_limit {
         debug!("project: overflow!");
         return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
@@ -932,7 +934,7 @@
     let infcx = selcx.infcx();
     for predicate in env_predicates {
         debug!("assemble_candidates_from_predicates: predicate={:?}", predicate);
-        if let ty::Predicate::Projection(data) = predicate {
+        if let &ty::PredicateKind::Projection(data) = predicate.kind() {
             let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
 
             let is_match = same_def_id
@@ -1202,20 +1204,19 @@
             object_ty
         ),
     };
-    let env_predicates =
-        data.projection_bounds().map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate());
+    let env_predicates = data
+        .projection_bounds()
+        .map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate(selcx.tcx()));
     let env_predicate = {
         let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
 
         // select only those projections that are actually projecting an
         // item with the correct name
-        let env_predicates = env_predicates.filter_map(|o| match o.predicate {
-            ty::Predicate::Projection(data) => {
-                if data.projection_def_id() == obligation.predicate.item_def_id {
-                    Some(data)
-                } else {
-                    None
-                }
+        let env_predicates = env_predicates.filter_map(|o| match o.predicate.kind() {
+            &ty::PredicateKind::Projection(data)
+                if data.projection_def_id() == obligation.predicate.item_def_id =>
+            {
+                Some(data)
             }
             _ => None,
         });
diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs
index 3b985a4..008ca8d 100644
--- a/src/librustc_trait_selection/traits/query/normalize.rs
+++ b/src/librustc_trait_selection/traits/query/normalize.rs
@@ -108,7 +108,7 @@
                     Reveal::UserFacing => ty,
 
                     Reveal::All => {
-                        let recursion_limit = *self.tcx().sess.recursion_limit.get();
+                        let recursion_limit = self.tcx().sess.recursion_limit();
                         if self.anon_depth >= recursion_limit {
                             let obligation = Obligation::with_depth(
                                 self.cause.clone(),
diff --git a/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs b/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs
index 981745a..5c8719d 100644
--- a/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs
+++ b/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs
@@ -1,6 +1,6 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
-use rustc_middle::ty::{ParamEnvAnd, Predicate, TyCtxt};
+use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
 
 pub use rustc_middle::traits::query::type_op::ProvePredicate;
 
@@ -15,7 +15,7 @@
         // `&T`, accounts for about 60% percentage of the predicates
         // we have to prove. No need to canonicalize and all that for
         // such cases.
-        if let Predicate::Trait(trait_ref, _) = key.value.predicate {
+        if let ty::PredicateKind::Trait(trait_ref, _) = key.value.predicate.kind() {
             if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
                 if trait_ref.def_id() == sized_def_id {
                     if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) {
diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs
index d903779..b402aba 100644
--- a/src/librustc_trait_selection/traits/select.rs
+++ b/src/librustc_trait_selection/traits/select.rs
@@ -414,14 +414,14 @@
             None => self.check_recursion_limit(&obligation, &obligation)?,
         }
 
-        match obligation.predicate {
-            ty::Predicate::Trait(ref t, _) => {
+        match obligation.predicate.kind() {
+            ty::PredicateKind::Trait(t, _) => {
                 debug_assert!(!t.has_escaping_bound_vars());
                 let obligation = obligation.with(*t);
                 self.evaluate_trait_predicate_recursively(previous_stack, obligation)
             }
 
-            ty::Predicate::Subtype(ref p) => {
+            ty::PredicateKind::Subtype(p) => {
                 // Does this code ever run?
                 match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
                     Some(Ok(InferOk { mut obligations, .. })) => {
@@ -436,7 +436,7 @@
                 }
             }
 
-            ty::Predicate::WellFormed(ty) => match wf::obligations(
+            &ty::PredicateKind::WellFormed(ty) => match wf::obligations(
                 self.infcx,
                 obligation.param_env,
                 obligation.cause.body_id,
@@ -450,12 +450,12 @@
                 None => Ok(EvaluatedToAmbig),
             },
 
-            ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => {
+            ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::RegionOutlives(..) => {
                 // We do not consider region relationships when evaluating trait matches.
                 Ok(EvaluatedToOkModuloRegions)
             }
 
-            ty::Predicate::ObjectSafe(trait_def_id) => {
+            &ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 if self.tcx().is_object_safe(trait_def_id) {
                     Ok(EvaluatedToOk)
                 } else {
@@ -463,7 +463,7 @@
                 }
             }
 
-            ty::Predicate::Projection(ref data) => {
+            ty::PredicateKind::Projection(data) => {
                 let project_obligation = obligation.with(*data);
                 match project::poly_project_and_unify_type(self, &project_obligation) {
                     Ok(Some(mut subobligations)) => {
@@ -484,7 +484,7 @@
                 }
             }
 
-            ty::Predicate::ClosureKind(_, closure_substs, kind) => {
+            &ty::PredicateKind::ClosureKind(_, closure_substs, kind) => {
                 match self.infcx.closure_kind(closure_substs) {
                     Some(closure_kind) => {
                         if closure_kind.extends(kind) {
@@ -497,7 +497,7 @@
                 }
             }
 
-            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+            &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
                 match self.tcx().const_eval_resolve(
                     obligation.param_env,
                     def_id,
@@ -511,7 +511,7 @@
                 }
             }
 
-            ty::Predicate::ConstEquate(c1, c2) => {
+            ty::PredicateKind::ConstEquate(c1, c2) => {
                 debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2);
 
                 let evaluate = |c: &'tcx ty::Const<'tcx>| {
@@ -676,8 +676,10 @@
             // trait refs. This is important because it's only a cycle
             // if the regions match exactly.
             let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
+            let tcx = self.tcx();
             let cycle = cycle.map(|stack| {
-                ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst)
+                ty::PredicateKind::Trait(stack.obligation.predicate, hir::Constness::NotConst)
+                    .to_predicate(tcx)
             });
             if self.coinductive_match(cycle) {
                 debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref);
@@ -792,8 +794,8 @@
     }
 
     fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
-        let result = match predicate {
-            ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
+        let result = match predicate.kind() {
+            ty::PredicateKind::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
             _ => false,
         };
         debug!("coinductive_predicate({:?}) = {:?}", predicate, result);
@@ -917,8 +919,7 @@
         obligation: &Obligation<'tcx, T>,
         error_obligation: &Obligation<'tcx, V>,
     ) -> Result<(), OverflowError> {
-        let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
-        if obligation.recursion_depth >= recursion_limit {
+        if obligation.recursion_depth >= self.infcx.tcx.sess.recursion_limit() {
             match self.query_mode {
                 TraitQueryMode::Standard => {
                     self.infcx().report_overflow_error(error_obligation, true);
@@ -2926,7 +2927,8 @@
             obligations.push(Obligation::new(
                 obligation.cause.clone(),
                 obligation.param_env,
-                ty::Predicate::ClosureKind(closure_def_id, substs, kind),
+                ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)
+                    .to_predicate(self.tcx()),
             ));
         }
 
@@ -3036,7 +3038,7 @@
                     cause,
                     obligation.recursion_depth + 1,
                     obligation.param_env,
-                    ty::Binder::bind(outlives).to_predicate(),
+                    ty::Binder::bind(outlives).to_predicate(tcx),
                 ));
             }
 
@@ -3079,12 +3081,12 @@
                     tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
                     tcx.mk_substs_trait(source, &[]),
                 );
-                nested.push(predicate_to_obligation(tr.without_const().to_predicate()));
+                nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx)));
 
                 // If the type is `Foo + 'a`, ensure that the type
                 // being cast to `Foo + 'a` outlives `'a`:
                 let outlives = ty::OutlivesPredicate(source, r);
-                nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate()));
+                nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate(tcx)));
             }
 
             // `[T; n]` -> `[T]`
diff --git a/src/librustc_trait_selection/traits/util.rs b/src/librustc_trait_selection/traits/util.rs
index eff73cf..f2d3f0e 100644
--- a/src/librustc_trait_selection/traits/util.rs
+++ b/src/librustc_trait_selection/traits/util.rs
@@ -97,7 +97,7 @@
     fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
         let tcx = self.tcx;
         let trait_ref = item.trait_ref();
-        let pred = trait_ref.without_const().to_predicate();
+        let pred = trait_ref.without_const().to_predicate(tcx);
 
         debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
 
@@ -110,7 +110,7 @@
         // Don't recurse if this trait alias is already on the stack for the DFS search.
         let anon_pred = anonymize_predicate(tcx, &pred);
         if item.path.iter().rev().skip(1).any(|(tr, _)| {
-            anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred
+            anonymize_predicate(tcx, &tr.without_const().to_predicate(tcx)) == anon_pred
         }) {
             return false;
         }
@@ -234,6 +234,7 @@
 }
 
 pub fn predicate_for_trait_ref<'tcx>(
+    tcx: TyCtxt<'tcx>,
     cause: ObligationCause<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
@@ -243,7 +244,7 @@
         cause,
         param_env,
         recursion_depth,
-        predicate: trait_ref.without_const().to_predicate(),
+        predicate: trait_ref.without_const().to_predicate(tcx),
     }
 }
 
@@ -258,7 +259,7 @@
 ) -> PredicateObligation<'tcx> {
     let trait_ref =
         ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) };
-    predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
+    predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth)
 }
 
 /// Casts a trait reference into a reference to one of its super
diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs
index 4d3bbfa..5118859 100644
--- a/src/librustc_trait_selection/traits/wf.rs
+++ b/src/librustc_trait_selection/traits/wf.rs
@@ -72,29 +72,29 @@
     let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
 
     // (*) ok to skip binders, because wf code is prepared for it
-    match *predicate {
-        ty::Predicate::Trait(ref t, _) => {
+    match predicate.kind() {
+        ty::PredicateKind::Trait(t, _) => {
             wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*)
         }
-        ty::Predicate::RegionOutlives(..) => {}
-        ty::Predicate::TypeOutlives(ref t) => {
+        ty::PredicateKind::RegionOutlives(..) => {}
+        ty::PredicateKind::TypeOutlives(t) => {
             wf.compute(t.skip_binder().0);
         }
-        ty::Predicate::Projection(ref t) => {
+        ty::PredicateKind::Projection(t) => {
             let t = t.skip_binder(); // (*)
             wf.compute_projection(t.projection_ty);
             wf.compute(t.ty);
         }
-        ty::Predicate::WellFormed(t) => {
+        &ty::PredicateKind::WellFormed(t) => {
             wf.compute(t);
         }
-        ty::Predicate::ObjectSafe(_) => {}
-        ty::Predicate::ClosureKind(..) => {}
-        ty::Predicate::Subtype(ref data) => {
+        ty::PredicateKind::ObjectSafe(_) => {}
+        ty::PredicateKind::ClosureKind(..) => {}
+        ty::PredicateKind::Subtype(data) => {
             wf.compute(data.skip_binder().a); // (*)
             wf.compute(data.skip_binder().b); // (*)
         }
-        ty::Predicate::ConstEvaluatable(def_id, substs) => {
+        &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
             let obligations = wf.nominal_obligations(def_id, substs);
             wf.out.extend(obligations);
 
@@ -102,7 +102,7 @@
                 wf.compute(ty);
             }
         }
-        ty::Predicate::ConstEquate(c1, c2) => {
+        ty::PredicateKind::ConstEquate(c1, c2) => {
             wf.compute(c1.ty);
             wf.compute(c2.ty);
         }
@@ -170,8 +170,8 @@
             hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::TyAlias(ty) => ty.span,
             _ => impl_item_ref.span,
         };
-    match pred {
-        ty::Predicate::Projection(proj) => {
+    match pred.kind() {
+        ty::PredicateKind::Projection(proj) => {
             // The obligation comes not from the current `impl` nor the `trait` being
             // implemented, but rather from a "second order" obligation, like in
             // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`.
@@ -194,7 +194,7 @@
                 }
             }
         }
-        ty::Predicate::Trait(pred, _) => {
+        ty::PredicateKind::Trait(pred, _) => {
             // An associated item obligation born out of the `trait` failed to be met. An example
             // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
             debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
@@ -216,6 +216,10 @@
 }
 
 impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
     fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
         traits::ObligationCause::new(self.span, self.body_id, code)
     }
@@ -275,8 +279,15 @@
             self.out.extend(obligations);
         }
 
+        let tcx = self.tcx();
         self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map(
-            |ty| traits::Obligation::new(cause.clone(), param_env, ty::Predicate::WellFormed(ty)),
+            |ty| {
+                traits::Obligation::new(
+                    cause.clone(),
+                    param_env,
+                    ty::PredicateKind::WellFormed(ty).to_predicate(tcx),
+                )
+            },
         ));
     }
 
@@ -290,7 +301,7 @@
         self.compute_trait_ref(&trait_ref, Elaborate::None);
 
         if !data.has_escaping_bound_vars() {
-            let predicate = trait_ref.without_const().to_predicate();
+            let predicate = trait_ref.without_const().to_predicate(self.infcx.tcx);
             let cause = self.cause(traits::ProjectionWf(data));
             self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
         }
@@ -305,7 +316,8 @@
             let obligations = self.nominal_obligations(def_id, substs);
             self.out.extend(obligations);
 
-            let predicate = ty::Predicate::ConstEvaluatable(def_id, substs);
+            let predicate =
+                ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx());
             let cause = self.cause(traits::MiscObligation);
             self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
         }
@@ -321,7 +333,7 @@
             self.out.push(traits::Obligation::new(
                 cause,
                 self.param_env,
-                trait_ref.without_const().to_predicate(),
+                trait_ref.without_const().to_predicate(self.infcx.tcx),
             ));
         }
     }
@@ -411,9 +423,10 @@
                         self.out.push(traits::Obligation::new(
                             cause,
                             param_env,
-                            ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
-                                rty, r,
-                            ))),
+                            ty::PredicateKind::TypeOutlives(ty::Binder::dummy(
+                                ty::OutlivesPredicate(rty, r),
+                            ))
+                            .to_predicate(self.tcx()),
                         ));
                     }
                 }
@@ -493,16 +506,17 @@
                     // obligations that don't refer to Self and
                     // checking those
 
-                    let defer_to_coercion = self.infcx.tcx.features().object_safe_for_dispatch;
+                    let defer_to_coercion = self.tcx().features().object_safe_for_dispatch;
 
                     if !defer_to_coercion {
                         let cause = self.cause(traits::MiscObligation);
                         let component_traits = data.auto_traits().chain(data.principal_def_id());
+                        let tcx = self.tcx();
                         self.out.extend(component_traits.map(|did| {
                             traits::Obligation::new(
                                 cause.clone(),
                                 param_env,
-                                ty::Predicate::ObjectSafe(did),
+                                ty::PredicateKind::ObjectSafe(did).to_predicate(tcx),
                             )
                         }));
                     }
@@ -528,7 +542,7 @@
                         self.out.push(traits::Obligation::new(
                             cause,
                             param_env,
-                            ty::Predicate::WellFormed(ty),
+                            ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx()),
                         ));
                     } else {
                         // Yes, resolved, proceed with the result.
@@ -608,7 +622,7 @@
                 self.out.push(traits::Obligation::new(
                     cause,
                     self.param_env,
-                    outlives.to_predicate(),
+                    outlives.to_predicate(self.infcx.tcx),
                 ));
             }
         }
diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs
index 184b9a9..a33ada2 100644
--- a/src/librustc_traits/chalk/lowering.rs
+++ b/src/librustc_traits/chalk/lowering.rs
@@ -38,8 +38,7 @@
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{GenericArg, SubstsRef};
 use rustc_middle::ty::{
-    self, Binder, BoundRegion, Predicate, Region, RegionKind, Ty, TyCtxt, TyKind, TypeFoldable,
-    TypeVisitor,
+    self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TyKind, TypeFoldable, TypeVisitor,
 };
 use rustc_span::def_id::DefId;
 
@@ -78,8 +77,8 @@
     ) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> {
         let clauses = self.environment.into_iter().filter_map(|clause| match clause {
             ChalkEnvironmentClause::Predicate(predicate) => {
-                match predicate {
-                    ty::Predicate::Trait(predicate, _) => {
+                match &predicate.kind() {
+                    ty::PredicateKind::Trait(predicate, _) => {
                         let (predicate, binders, _named_regions) =
                             collect_bound_vars(interner, interner.tcx, predicate);
 
@@ -100,9 +99,9 @@
                         )
                     }
                     // FIXME(chalk): need to add RegionOutlives/TypeOutlives
-                    ty::Predicate::RegionOutlives(_) => None,
-                    ty::Predicate::TypeOutlives(_) => None,
-                    ty::Predicate::Projection(predicate) => {
+                    ty::PredicateKind::RegionOutlives(_) => None,
+                    ty::PredicateKind::TypeOutlives(_) => None,
+                    ty::PredicateKind::Projection(predicate) => {
                         let (predicate, binders, _named_regions) =
                             collect_bound_vars(interner, interner.tcx, predicate);
 
@@ -122,12 +121,14 @@
                             .intern(interner),
                         )
                     }
-                    ty::Predicate::WellFormed(..)
-                    | ty::Predicate::ObjectSafe(..)
-                    | ty::Predicate::ClosureKind(..)
-                    | ty::Predicate::Subtype(..)
-                    | ty::Predicate::ConstEvaluatable(..)
-                    | ty::Predicate::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
+                    ty::PredicateKind::WellFormed(..)
+                    | ty::PredicateKind::ObjectSafe(..)
+                    | ty::PredicateKind::ClosureKind(..)
+                    | ty::PredicateKind::Subtype(..)
+                    | ty::PredicateKind::ConstEvaluatable(..)
+                    | ty::PredicateKind::ConstEquate(..) => {
+                        bug!("unexpected predicate {}", predicate)
+                    }
                 }
             }
             ChalkEnvironmentClause::TypeFromEnv(ty) => Some(
@@ -154,17 +155,17 @@
 
 impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predicate<'tcx> {
     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> {
-        match self {
-            Predicate::Trait(predicate, _) => predicate.lower_into(interner),
+        match self.kind() {
+            ty::PredicateKind::Trait(predicate, _) => predicate.lower_into(interner),
             // FIXME(chalk): we need to register constraints.
-            Predicate::RegionOutlives(_predicate) => {
+            ty::PredicateKind::RegionOutlives(_predicate) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
             }
-            Predicate::TypeOutlives(_predicate) => {
+            ty::PredicateKind::TypeOutlives(_predicate) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
             }
-            Predicate::Projection(predicate) => predicate.lower_into(interner),
-            Predicate::WellFormed(ty) => match ty.kind {
+            ty::PredicateKind::Projection(predicate) => predicate.lower_into(interner),
+            ty::PredicateKind::WellFormed(ty) => match ty.kind {
                 // These types are always WF.
                 ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => {
                     chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
@@ -188,11 +189,13 @@
             //
             // We can defer this, but ultimately we'll want to express
             // some of these in terms of chalk operations.
-            Predicate::ObjectSafe(..)
-            | Predicate::ClosureKind(..)
-            | Predicate::Subtype(..)
-            | Predicate::ConstEvaluatable(..)
-            | Predicate::ConstEquate(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)),
+            ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..) => {
+                chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
+            }
         }
     }
 }
@@ -391,7 +394,6 @@
                 ty::BrEnv => unimplemented!(),
             },
             ReFree(_) => unimplemented!(),
-            ReScope(_) => unimplemented!(),
             ReStatic => unimplemented!(),
             ReVar(_) => unimplemented!(),
             RePlaceholder(placeholder_region) => {
@@ -439,8 +441,8 @@
         self,
         interner: &RustInterner<'tcx>,
     ) -> Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
-        match &self {
-            Predicate::Trait(predicate, _) => {
+        match &self.kind() {
+            ty::PredicateKind::Trait(predicate, _) => {
                 let (predicate, binders, _named_regions) =
                     collect_bound_vars(interner, interner.tcx, predicate);
 
@@ -449,16 +451,16 @@
                     chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)),
                 ))
             }
-            Predicate::RegionOutlives(_predicate) => None,
-            Predicate::TypeOutlives(_predicate) => None,
-            Predicate::Projection(_predicate) => None,
-            Predicate::WellFormed(_ty) => None,
+            ty::PredicateKind::RegionOutlives(_predicate) => None,
+            ty::PredicateKind::TypeOutlives(_predicate) => None,
+            ty::PredicateKind::Projection(_predicate) => None,
+            ty::PredicateKind::WellFormed(_ty) => None,
 
-            Predicate::ObjectSafe(..)
-            | Predicate::ClosureKind(..)
-            | Predicate::Subtype(..)
-            | Predicate::ConstEvaluatable(..)
-            | Predicate::ConstEquate(..) => bug!("unexpected predicate {}", &self),
+            ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", &self),
         }
     }
 }
diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs
index 08475d6..fb9c0d7 100644
--- a/src/librustc_traits/dropck_outlives.rs
+++ b/src/librustc_traits/dropck_outlives.rs
@@ -163,7 +163,7 @@
 ) -> Result<(), NoSolution> {
     debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty);
 
-    if depth >= *tcx.sess.recursion_limit.get() {
+    if depth >= tcx.sess.recursion_limit() {
         constraints.overflows.push(ty);
         return Ok(());
     }
diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs
index eaaab87..5dee71a 100644
--- a/src/librustc_traits/implied_outlives_bounds.rs
+++ b/src/librustc_traits/implied_outlives_bounds.rs
@@ -94,28 +94,28 @@
         // region relationships.
         implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
             assert!(!obligation.has_escaping_bound_vars());
-            match obligation.predicate {
-                ty::Predicate::Trait(..)
-                | ty::Predicate::Subtype(..)
-                | ty::Predicate::Projection(..)
-                | ty::Predicate::ClosureKind(..)
-                | ty::Predicate::ObjectSafe(..)
-                | ty::Predicate::ConstEvaluatable(..)
-                | ty::Predicate::ConstEquate(..) => vec![],
+            match obligation.predicate.kind() {
+                ty::PredicateKind::Trait(..)
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Projection(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..) => vec![],
 
-                ty::Predicate::WellFormed(subty) => {
+                ty::PredicateKind::WellFormed(subty) => {
                     wf_types.push(subty);
                     vec![]
                 }
 
-                ty::Predicate::RegionOutlives(ref data) => match data.no_bound_vars() {
+                ty::PredicateKind::RegionOutlives(ref data) => match data.no_bound_vars() {
                     None => vec![],
                     Some(ty::OutlivesPredicate(r_a, r_b)) => {
                         vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
                     }
                 },
 
-                ty::Predicate::TypeOutlives(ref data) => match data.no_bound_vars() {
+                ty::PredicateKind::TypeOutlives(ref data) => match data.no_bound_vars() {
                     None => vec![],
                     Some(ty::OutlivesPredicate(ty_a, r_b)) => {
                         let ty_a = infcx.resolve_vars_if_possible(&ty_a);
diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs
index ed30ed5..fcb7514 100644
--- a/src/librustc_traits/normalize_erasing_regions.rs
+++ b/src/librustc_traits/normalize_erasing_regions.rs
@@ -40,15 +40,15 @@
 }
 
 fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool {
-    match p {
-        ty::Predicate::RegionOutlives(..) | ty::Predicate::TypeOutlives(..) => false,
-        ty::Predicate::Trait(..)
-        | ty::Predicate::Projection(..)
-        | ty::Predicate::WellFormed(..)
-        | ty::Predicate::ObjectSafe(..)
-        | ty::Predicate::ClosureKind(..)
-        | ty::Predicate::Subtype(..)
-        | ty::Predicate::ConstEvaluatable(..)
-        | ty::Predicate::ConstEquate(..) => true,
+    match p.kind() {
+        ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
+        ty::PredicateKind::Trait(..)
+        | ty::PredicateKind::Projection(..)
+        | ty::PredicateKind::WellFormed(..)
+        | ty::PredicateKind::ObjectSafe(..)
+        | ty::PredicateKind::ClosureKind(..)
+        | ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::ConstEquate(..) => true,
     }
 }
diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs
index aeb31c2..22077b4 100644
--- a/src/librustc_traits/type_op.rs
+++ b/src/librustc_traits/type_op.rs
@@ -6,9 +6,8 @@
 use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts};
-use rustc_middle::ty::{
-    FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance,
-};
+use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance};
+use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -140,7 +139,9 @@
 
             self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
 
-            self.prove_predicate(Predicate::WellFormed(impl_self_ty));
+            self.prove_predicate(
+                ty::PredicateKind::WellFormed(impl_self_ty).to_predicate(self.tcx()),
+            );
         }
 
         // In addition to proving the predicates, we have to
@@ -154,7 +155,7 @@
         // them?  This would only be relevant if some input
         // type were ill-formed but did not appear in `ty`,
         // which...could happen with normalization...
-        self.prove_predicate(Predicate::WellFormed(ty));
+        self.prove_predicate(ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx()));
         Ok(())
     }
 }
diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs
index 97994b4..e94a47f 100644
--- a/src/librustc_ty/needs_drop.rs
+++ b/src/librustc_ty/needs_drop.rs
@@ -43,14 +43,13 @@
     ) -> Self {
         let mut seen_tys = FxHashSet::default();
         seen_tys.insert(ty);
-        let recursion_limit = *tcx.sess.recursion_limit.get();
         Self {
             tcx,
             param_env,
             seen_tys,
             query_ty: ty,
             unchecked_tys: vec![(ty, 0)],
-            recursion_limit,
+            recursion_limit: tcx.sess.recursion_limit(),
             adt_components,
         }
     }
diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs
index 1aa11a7..3da5da2d 100644
--- a/src/librustc_ty/ty.rs
+++ b/src/librustc_ty/ty.rs
@@ -61,7 +61,7 @@
                 substs: tcx.mk_substs_trait(ty, &[]),
             })
             .without_const()
-            .to_predicate();
+            .to_predicate(tcx);
             let predicates = tcx.predicates_of(adtdef.did).predicates;
             if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] }
         }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 6529d78..9a5fe95 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1596,8 +1596,8 @@
                     "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
                     obligation.predicate
                 );
-                match obligation.predicate {
-                    ty::Predicate::Trait(pred, _) => {
+                match obligation.predicate.kind() {
+                    ty::PredicateKind::Trait(pred, _) => {
                         associated_types.entry(span).or_default().extend(
                             tcx.associated_items(pred.def_id())
                                 .in_definition_order()
@@ -1605,7 +1605,7 @@
                                 .map(|item| item.def_id),
                         );
                     }
-                    ty::Predicate::Projection(pred) => {
+                    &ty::PredicateKind::Projection(pred) => {
                         // A `Self` within the original bound will be substituted with a
                         // `trait_object_dummy_self`, so check for that.
                         let references_self =
@@ -3042,7 +3042,7 @@
                     def_id: sized,
                     substs: tcx.mk_substs_trait(param_ty, &[]),
                 });
-                (trait_ref.without_const().to_predicate(), span)
+                (trait_ref.without_const().to_predicate(tcx), span)
             })
         });
 
@@ -3057,16 +3057,16 @@
                         // or it's a generic associated type that deliberately has escaping bound vars.
                         let region_bound = ty::fold::shift_region(tcx, region_bound, 1);
                         let outlives = ty::OutlivesPredicate(param_ty, region_bound);
-                        (ty::Binder::bind(outlives).to_predicate(), span)
+                        (ty::Binder::bind(outlives).to_predicate(tcx), span)
                     })
                     .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
-                        let predicate = bound_trait_ref.with_constness(constness).to_predicate();
+                        let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
                         (predicate, span)
                     }))
                     .chain(
                         self.projection_bounds
                             .iter()
-                            .map(|&(projection, span)| (projection.to_predicate(), span)),
+                            .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
                     ),
             )
             .collect()
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 16af168..fb139b5 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -436,6 +436,8 @@
 
         if let Some(m) = contains_ref_bindings {
             self.check_expr_with_needs(scrut, Needs::maybe_mut_place(m))
+        } else if arms.is_empty() {
+            self.check_expr(scrut)
         } else {
             // ...but otherwise we want to use any supertype of the
             // scrutinee. This is sort of a workaround, see note (*) in
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index ae6c173..d4c01a8 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -48,7 +48,7 @@
             return Some((self.cur_ty, 0));
         }
 
-        if self.steps.len() >= *tcx.sess.recursion_limit.get() {
+        if self.steps.len() >= tcx.sess.recursion_limit() {
             if !self.silence_errors {
                 report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
             }
@@ -125,7 +125,7 @@
         let obligation = traits::Obligation::new(
             cause.clone(),
             self.param_env,
-            trait_ref.without_const().to_predicate(),
+            trait_ref.without_const().to_predicate(tcx),
         );
         if !self.infcx.predicate_may_hold(&obligation) {
             debug!("overloaded_deref_ty: cannot match obligation");
@@ -236,7 +236,7 @@
 
 pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
     // We've reached the recursion limit, error gracefully.
-    let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
+    let suggested_limit = tcx.sess.recursion_limit() * 2;
     let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
     let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
     let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 87a6f11..8fa901d 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -3,7 +3,6 @@
 use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
 use crate::astconv::AstConv;
-use crate::middle::region;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::{FutureTraitLangItem, GeneratorTraitLangItem};
@@ -17,7 +16,6 @@
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::ArgKind;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::Obligation;
 use std::cmp;
 use std::iter;
 
@@ -206,7 +204,9 @@
                     obligation.predicate
                 );
 
-                if let ty::Predicate::Projection(ref proj_predicate) = obligation.predicate {
+                if let ty::PredicateKind::Projection(ref proj_predicate) =
+                    obligation.predicate.kind()
+                {
                     // Given a Projection predicate, we can potentially infer
                     // the complete signature.
                     self.deduce_sig_from_projection(Some(obligation.cause.span), proj_predicate)
@@ -516,21 +516,6 @@
                 let InferOk { value: (), obligations } =
                     self.at(&cause, self.param_env).eq(*expected_ty, supplied_ty)?;
                 all_obligations.extend(obligations);
-
-                // Also, require that the supplied type must outlive
-                // the closure body.
-                let closure_body_region = self.tcx.mk_region(ty::ReScope(region::Scope {
-                    id: body.value.hir_id.local_id,
-                    data: region::ScopeData::Node,
-                }));
-                all_obligations.push(Obligation::new(
-                    cause,
-                    self.param_env,
-                    ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
-                        supplied_ty,
-                        closure_body_region,
-                    ))),
-                ));
             }
 
             let (supplied_output_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars(
@@ -641,7 +626,7 @@
         // where R is the return type we are expecting. This type `T`
         // will be our output.
         let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
-            if let ty::Predicate::Projection(ref proj_predicate) = obligation.predicate {
+            if let ty::PredicateKind::Projection(ref proj_predicate) = obligation.predicate.kind() {
                 self.deduce_future_output_from_projection(obligation.cause.span, proj_predicate)
             } else {
                 None
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 54562cf..a324bd0 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -596,8 +596,10 @@
         while !queue.is_empty() {
             let obligation = queue.remove(0);
             debug!("coerce_unsized resolve step: {:?}", obligation);
-            let trait_pred = match obligation.predicate {
-                ty::Predicate::Trait(trait_pred, _) if traits.contains(&trait_pred.def_id()) => {
+            let trait_pred = match obligation.predicate.kind() {
+                &ty::PredicateKind::Trait(trait_pred, _)
+                    if traits.contains(&trait_pred.def_id()) =>
+                {
                     if unsize_did == trait_pred.def_id() {
                         let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
                         if let ty::Tuple(..) = unsize_ty.kind {
@@ -885,7 +887,7 @@
         let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
         coerce
             .autoderef(rustc_span::DUMMY_SP, expr_ty)
-            .find_map(|(ty, steps)| coerce.unify(ty, target).ok().map(|_| steps))
+            .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
     }
 
     /// Given some expressions, their known unified type and another expression,
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 9694ce9..700b935 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -1,13 +1,12 @@
 use crate::check::FnCtxt;
 use rustc_infer::infer::InferOk;
 use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCause};
+use rustc_trait_selection::traits::ObligationCause;
 
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
-use rustc_hir::lang_items::{CloneTraitLangItem, DerefTraitLangItem};
+use rustc_hir::lang_items::CloneTraitLangItem;
 use rustc_hir::{is_range_literal, Node};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
@@ -633,47 +632,29 @@
                 }
             }
             _ if sp == expr.span && !is_macro => {
-                // Check for `Deref` implementations by constructing a predicate to
-                // prove: `<T as Deref>::Output == U`
-                let deref_trait = self.tcx.require_lang_item(DerefTraitLangItem, Some(sp));
-                let item_def_id = self
-                    .tcx
-                    .associated_items(deref_trait)
-                    .in_definition_order()
-                    .find(|item| item.kind == ty::AssocKind::Type)
-                    .unwrap()
-                    .def_id;
-                let predicate =
-                    ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate {
-                        // `<T as Deref>::Output`
-                        projection_ty: ty::ProjectionTy {
-                            // `T`
-                            substs: self.tcx.intern_substs(&[checked_ty.into()]),
-                            // `Deref::Output`
-                            item_def_id,
-                        },
-                        // `U`
-                        ty: expected,
-                    }));
-                let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
-                let impls_deref = self.infcx.predicate_may_hold(&obligation);
-
-                // For a suggestion to make sense, the type would need to be `Copy`.
-                let is_copy = self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp);
-
-                if is_copy && impls_deref {
-                    if let Ok(code) = sm.span_to_snippet(sp) {
-                        let message = if checked_ty.is_region_ptr() {
-                            "consider dereferencing the borrow"
-                        } else {
-                            "consider dereferencing the type"
-                        };
-                        let suggestion = if is_struct_pat_shorthand_field {
-                            format!("{}: *{}", code, code)
-                        } else {
-                            format!("*{}", code)
-                        };
-                        return Some((sp, message, suggestion, Applicability::MachineApplicable));
+                if let Some(steps) = self.deref_steps(checked_ty, expected) {
+                    if steps == 1 {
+                        // For a suggestion to make sense, the type would need to be `Copy`.
+                        if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp) {
+                            if let Ok(code) = sm.span_to_snippet(sp) {
+                                let message = if checked_ty.is_region_ptr() {
+                                    "consider dereferencing the borrow"
+                                } else {
+                                    "consider dereferencing the type"
+                                };
+                                let suggestion = if is_struct_pat_shorthand_field {
+                                    format!("{}: *{}", code, code)
+                                } else {
+                                    format!("*{}", code)
+                                };
+                                return Some((
+                                    sp,
+                                    message,
+                                    suggestion,
+                                    Applicability::MachineApplicable,
+                                ));
+                            }
+                        }
                     }
                 }
             }
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 478a848..24c319f 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -5,7 +5,6 @@
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferOk, RegionckMode, TyCtxtInferExt};
 use rustc_infer::traits::TraitEngineExt as _;
-use rustc_middle::middle::region;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::{Subst, SubstsRef};
@@ -120,8 +119,6 @@
             return Err(ErrorReported);
         }
 
-        let region_scope_tree = region::ScopeTree::default();
-
         // NB. It seems a bit... suspicious to use an empty param-env
         // here. The correct thing, I imagine, would be
         // `OutlivesEnvironment::new(impl_param_env)`, which would
@@ -134,7 +131,6 @@
 
         infcx.resolve_regions_and_report_errors(
             drop_impl_did.to_def_id(),
-            &region_scope_tree,
             &outlives_env,
             RegionckMode::default(),
         );
@@ -230,9 +226,11 @@
         // could be extended easily also to the other `Predicate`.
         let predicate_matches_closure = |p: &'_ Predicate<'tcx>| {
             let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
-            match (predicate, p) {
-                (Predicate::Trait(a, _), Predicate::Trait(b, _)) => relator.relate(a, b).is_ok(),
-                (Predicate::Projection(a), Predicate::Projection(b)) => {
+            match (predicate.kind(), p.kind()) {
+                (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => {
+                    relator.relate(a, b).is_ok()
+                }
+                (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
                     relator.relate(a, b).is_ok()
                 }
                 _ => predicate == p,
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index c4805c5..410c5ef 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -574,8 +574,8 @@
         };
 
         traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied())
-            .filter_map(|obligation| match obligation.predicate {
-                ty::Predicate::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
+            .filter_map(|obligation| match obligation.predicate.kind() {
+                ty::PredicateKind::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
                     let span = predicates
                         .predicates
                         .iter()
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index a254aec..aae02ea 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -324,7 +324,7 @@
             span,
             self.body_id,
             self.param_env,
-            poly_trait_ref.without_const().to_predicate(),
+            poly_trait_ref.without_const().to_predicate(self.tcx),
         );
 
         // Now we want to know if this can be matched
@@ -401,7 +401,7 @@
         obligations.push(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::Predicate::WellFormed(method_ty),
+            ty::PredicateKind::WellFormed(method_ty).to_predicate(tcx),
         ));
 
         let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig };
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index e21db90..91562d5 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -796,23 +796,26 @@
     fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
         // FIXME: do we want to commit to this behavior for param bounds?
 
-        let bounds = self.param_env.caller_bounds.iter().filter_map(|predicate| match *predicate {
-            ty::Predicate::Trait(ref trait_predicate, _) => {
-                match trait_predicate.skip_binder().trait_ref.self_ty().kind {
-                    ty::Param(ref p) if *p == param_ty => Some(trait_predicate.to_poly_trait_ref()),
-                    _ => None,
+        let bounds =
+            self.param_env.caller_bounds.iter().filter_map(|predicate| match predicate.kind() {
+                ty::PredicateKind::Trait(ref trait_predicate, _) => {
+                    match trait_predicate.skip_binder().trait_ref.self_ty().kind {
+                        ty::Param(ref p) if *p == param_ty => {
+                            Some(trait_predicate.to_poly_trait_ref())
+                        }
+                        _ => None,
+                    }
                 }
-            }
-            ty::Predicate::Subtype(..)
-            | ty::Predicate::Projection(..)
-            | ty::Predicate::RegionOutlives(..)
-            | ty::Predicate::WellFormed(..)
-            | ty::Predicate::ObjectSafe(..)
-            | ty::Predicate::ClosureKind(..)
-            | ty::Predicate::TypeOutlives(..)
-            | ty::Predicate::ConstEvaluatable(..)
-            | ty::Predicate::ConstEquate(..) => None,
-        });
+                ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Projection(..)
+                | ty::PredicateKind::RegionOutlives(..)
+                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::TypeOutlives(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..) => None,
+            });
 
         self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
             let trait_ref = this.erase_late_bound_regions(&poly_trait_ref);
@@ -1374,7 +1377,7 @@
                 }
 
                 TraitCandidate(trait_ref) => {
-                    let predicate = trait_ref.without_const().to_predicate();
+                    let predicate = trait_ref.without_const().to_predicate(self.tcx);
                     let obligation = traits::Obligation::new(cause, self.param_env, predicate);
                     if !self.predicate_may_hold(&obligation) {
                         result = ProbeResult::NoMatch;
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index cf26c94..7ca3eb8 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -58,7 +58,7 @@
                             span,
                             self.body_id,
                             self.param_env,
-                            poly_trait_ref.without_const().to_predicate(),
+                            poly_trait_ref.without_const().to_predicate(tcx),
                         );
                         self.predicate_may_hold(&obligation)
                     })
@@ -574,8 +574,8 @@
                     let mut bound_spans = vec![];
                     let mut collect_type_param_suggestions =
                         |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| {
-                            if let (ty::Param(_), ty::Predicate::Trait(p, _)) =
-                                (&self_ty.kind, parent_pred)
+                            if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) =
+                                (&self_ty.kind, parent_pred.kind())
                             {
                                 if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind {
                                     let node = def.did.as_local().map(|def_id| {
@@ -626,9 +626,9 @@
                             _ => {}
                         }
                     };
-                    let mut format_pred = |pred| {
-                        match pred {
-                            ty::Predicate::Projection(pred) => {
+                    let mut format_pred = |pred: ty::Predicate<'tcx>| {
+                        match pred.kind() {
+                            ty::PredicateKind::Projection(pred) => {
                                 // `<Foo as Iterator>::Item = String`.
                                 let trait_ref =
                                     pred.skip_binder().projection_ty.trait_ref(self.tcx);
@@ -646,7 +646,7 @@
                                 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
                                 Some((obligation, trait_ref.self_ty()))
                             }
-                            ty::Predicate::Trait(poly_trait_ref, _) => {
+                            ty::PredicateKind::Trait(poly_trait_ref, _) => {
                                 let p = poly_trait_ref.skip_binder().trait_ref;
                                 let self_ty = p.self_ty();
                                 let path = p.print_only_trait_path();
@@ -946,11 +946,11 @@
                 // this isn't perfect (that is, there are cases when
                 // implementing a trait would be legal but is rejected
                 // here).
-                unsatisfied_predicates.iter().all(|(p, _)| match p {
+                unsatisfied_predicates.iter().all(|(p, _)| match p.kind() {
                     // Hide traits if they are present in predicates as they can be fixed without
                     // having to implement them.
-                    ty::Predicate::Trait(t, _) => t.def_id() == info.def_id,
-                    ty::Predicate::Projection(p) => p.item_def_id() == info.def_id,
+                    ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
+                    ty::PredicateKind::Projection(p) => p.item_def_id() == info.def_id,
                     _ => false,
                 }) && (type_is_local || info.def_id.is_local())
                     && self
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d72c74e..6b7adb7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -106,13 +106,13 @@
 use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
+use rustc_infer::infer;
 use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_infer::infer::{self, InferCtxt, InferOk, InferResult, TyCtxtInferExt};
+use rustc_infer::infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TyCtxtInferExt};
 use rustc_middle::hir::map::blocks::FnLikeNode;
-use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -667,13 +667,6 @@
         let tcx = infcx.tcx;
         let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
         let body_id = tcx.hir().maybe_body_owned_by(item_id);
-        let implicit_region_bound = body_id.map(|body_id| {
-            let body = tcx.hir().body(body_id);
-            tcx.mk_region(ty::ReScope(region::Scope {
-                id: body.value.hir_id.local_id,
-                data: region::ScopeData::CallSite,
-            }))
-        });
 
         Inherited {
             tables: MaybeInProgressTables { maybe_tables: infcx.in_progress_tables },
@@ -686,7 +679,7 @@
             deferred_generator_interiors: RefCell::new(Vec::new()),
             opaque_types: RefCell::new(Default::default()),
             opaque_types_vars: RefCell::new(Default::default()),
-            implicit_region_bound,
+            implicit_region_bound: None,
             body_id,
         }
     }
@@ -1337,12 +1330,9 @@
     // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
     // (as it's created inside the body itself, not passed in from outside).
     let maybe_va_list = if fn_sig.c_variadic {
-        let va_list_did =
-            tcx.require_lang_item(VaListTypeLangItem, Some(body.params.last().unwrap().span));
-        let region = tcx.mk_region(ty::ReScope(region::Scope {
-            id: body.value.hir_id.local_id,
-            data: region::ScopeData::CallSite,
-        }));
+        let span = body.params.last().unwrap().span;
+        let va_list_did = tcx.require_lang_item(VaListTypeLangItem, Some(span));
+        let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
 
         Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()]))
     } else {
@@ -1458,7 +1448,7 @@
                 inherited.register_predicate(traits::Obligation::new(
                     cause,
                     param_env,
-                    trait_ref.without_const().to_predicate(),
+                    trait_ref.without_const().to_predicate(tcx),
                 ));
             }
         }
@@ -2223,8 +2213,8 @@
     let mut projections = vec![];
     for (predicate, _) in predicates.predicates {
         debug!("predicate {:?}", predicate);
-        match predicate {
-            ty::Predicate::Trait(trait_predicate, _) => {
+        match predicate.kind() {
+            ty::PredicateKind::Trait(trait_predicate, _) => {
                 let entry = types.entry(trait_predicate.skip_binder().self_ty()).or_default();
                 let def_id = trait_predicate.skip_binder().def_id();
                 if Some(def_id) != tcx.lang_items().sized_trait() {
@@ -2233,7 +2223,7 @@
                     entry.push(trait_predicate.skip_binder().def_id());
                 }
             }
-            ty::Predicate::Projection(projection_pred) => {
+            ty::PredicateKind::Projection(projection_pred) => {
                 projections.push(projection_pred);
             }
             _ => {}
@@ -2769,8 +2759,8 @@
         ty::GenericPredicates {
             parent: None,
             predicates: tcx.arena.alloc_from_iter(self.param_env.caller_bounds.iter().filter_map(
-                |&predicate| match predicate {
-                    ty::Predicate::Trait(ref data, _)
+                |&predicate| match predicate.kind() {
+                    ty::PredicateKind::Trait(ref data, _)
                         if data.skip_binder().self_ty().is_param(index) =>
                     {
                         // HACK(eddyb) should get the original `Span`.
@@ -3379,7 +3369,7 @@
             self.register_predicate(traits::Obligation::new(
                 cause,
                 self.param_env,
-                ty::Predicate::ConstEvaluatable(def_id, substs),
+                ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx),
             ));
         }
 
@@ -3428,7 +3418,7 @@
         self.register_predicate(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::Predicate::WellFormed(ty),
+            ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx),
         ));
     }
 
@@ -3857,18 +3847,20 @@
             .borrow()
             .pending_obligations()
             .into_iter()
-            .filter_map(move |obligation| match obligation.predicate {
-                ty::Predicate::Projection(ref data) => {
+            .filter_map(move |obligation| match obligation.predicate.kind() {
+                ty::PredicateKind::Projection(ref data) => {
                     Some((data.to_poly_trait_ref(self.tcx), obligation))
                 }
-                ty::Predicate::Trait(ref data, _) => Some((data.to_poly_trait_ref(), obligation)),
-                ty::Predicate::Subtype(..) => None,
-                ty::Predicate::RegionOutlives(..) => None,
-                ty::Predicate::TypeOutlives(..) => None,
-                ty::Predicate::WellFormed(..) => None,
-                ty::Predicate::ObjectSafe(..) => None,
-                ty::Predicate::ConstEvaluatable(..) => None,
-                ty::Predicate::ConstEquate(..) => None,
+                ty::PredicateKind::Trait(ref data, _) => {
+                    Some((data.to_poly_trait_ref(), obligation))
+                }
+                ty::PredicateKind::Subtype(..) => None,
+                ty::PredicateKind::RegionOutlives(..) => None,
+                ty::PredicateKind::TypeOutlives(..) => None,
+                ty::PredicateKind::WellFormed(..) => None,
+                ty::PredicateKind::ObjectSafe(..) => None,
+                ty::PredicateKind::ConstEvaluatable(..) => None,
+                ty::PredicateKind::ConstEquate(..) => None,
                 // N.B., this predicate is created by breaking down a
                 // `ClosureType: FnFoo()` predicate, where
                 // `ClosureType` represents some `Closure`. It can't
@@ -3877,7 +3869,7 @@
                 // this closure yet; this is exactly why the other
                 // code is looking for a self type of a unresolved
                 // inference variable.
-                ty::Predicate::ClosureKind(..) => None,
+                ty::PredicateKind::ClosureKind(..) => None,
             })
             .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
     }
@@ -4206,7 +4198,7 @@
                 continue;
             }
 
-            if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate {
+            if let ty::PredicateKind::Trait(predicate, _) = error.obligation.predicate.kind() {
                 // Collect the argument position for all arguments that could have caused this
                 // `FulfillmentError`.
                 let mut referenced_in = final_arg_types
@@ -4253,7 +4245,9 @@
             if let hir::ExprKind::Path(qpath) = &path.kind {
                 if let hir::QPath::Resolved(_, path) = &qpath {
                     for error in errors {
-                        if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate {
+                        if let ty::PredicateKind::Trait(predicate, _) =
+                            error.obligation.predicate.kind()
+                        {
                             // If any of the type arguments in this path segment caused the
                             // `FullfillmentError`, point at its span (#61860).
                             for arg in path
@@ -5322,10 +5316,11 @@
                 };
 
                 let predicate =
-                    ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate {
+                    ty::PredicateKind::Projection(ty::Binder::bind(ty::ProjectionPredicate {
                         projection_ty,
                         ty: expected,
-                    }));
+                    }))
+                    .to_predicate(self.tcx);
                 let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
 
                 debug!("suggest_missing_await: trying obligation {:?}", obligation);
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 049f476..90ba15a 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -83,12 +83,10 @@
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, RegionObligation, RegionckMode};
 use rustc_middle::ty::adjustment;
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 use rustc_trait_selection::infer::OutlivesEnvironmentExt;
 use rustc_trait_selection::opaque_types::InferCtxtExt;
-use std::mem;
 use std::ops::Deref;
 
 // a variation on try that just returns unit
@@ -111,8 +109,7 @@
     pub fn regionck_expr(&self, body: &'tcx hir::Body<'tcx>) {
         let subject = self.tcx.hir().body_owner_def_id(body.id());
         let id = body.value.hir_id;
-        let mut rcx =
-            RegionCtxt::new(self, RepeatingScope(id), id, Subject(subject), self.param_env);
+        let mut rcx = RegionCtxt::new(self, id, Subject(subject), self.param_env);
 
         // There are no add'l implied bounds when checking a
         // standalone expr (e.g., the `E` in a type like `[u32; E]`).
@@ -131,13 +128,7 @@
     pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: &[Ty<'tcx>]) {
         debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys);
         let subject = self.tcx.hir().local_def_id(item_id);
-        let mut rcx = RegionCtxt::new(
-            self,
-            RepeatingScope(item_id),
-            item_id,
-            Subject(subject),
-            self.param_env,
-        );
+        let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env);
         rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span);
         rcx.outlives_environment.save_implied_bounds(item_id);
         rcx.visit_region_obligations(item_id);
@@ -156,8 +147,7 @@
         debug!("regionck_fn(id={})", fn_id);
         let subject = self.tcx.hir().body_owner_def_id(body.id());
         let hir_id = body.value.hir_id;
-        let mut rcx =
-            RegionCtxt::new(self, RepeatingScope(hir_id), hir_id, Subject(subject), self.param_env);
+        let mut rcx = RegionCtxt::new(self, hir_id, Subject(subject), self.param_env);
 
         if !self.errors_reported_since_creation() {
             // regionck assumes typeck succeeded
@@ -182,12 +172,6 @@
     body_id: hir::HirId,
     body_owner: LocalDefId,
 
-    // call_site scope of innermost fn
-    call_site_scope: Option<region::Scope>,
-
-    // id of innermost fn or loop
-    repeating_scope: hir::HirId,
-
     // id of AST node being analyzed (the subject of the analysis).
     subject_def_id: LocalDefId,
 }
@@ -199,13 +183,11 @@
     }
 }
 
-pub struct RepeatingScope(hir::HirId);
 pub struct Subject(LocalDefId);
 
 impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
     pub fn new(
         fcx: &'a FnCtxt<'a, 'tcx>,
-        RepeatingScope(initial_repeating_scope): RepeatingScope,
         initial_body_id: hir::HirId,
         Subject(subject): Subject,
         param_env: ty::ParamEnv<'tcx>,
@@ -215,19 +197,13 @@
         RegionCtxt {
             fcx,
             region_scope_tree,
-            repeating_scope: initial_repeating_scope,
             body_id: initial_body_id,
             body_owner: subject,
-            call_site_scope: None,
             subject_def_id: subject,
             outlives_environment,
         }
     }
 
-    fn set_repeating_scope(&mut self, scope: hir::HirId) -> hir::HirId {
-        mem::replace(&mut self.repeating_scope, scope)
-    }
-
     /// Try to resolve the type for the given node, returning `t_err` if an error results. Note that
     /// we never care about the details of the error, the same error will be detected and reported
     /// in the writeback phase.
@@ -261,16 +237,10 @@
         self.resolve_type(t)
     }
 
-    /// Try to resolve the type for the given node.
-    pub fn resolve_expr_type_adjusted(&mut self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
-        let ty = self.tables.borrow().expr_ty_adjusted(expr);
-        self.resolve_type(ty)
-    }
-
-    /// This is the "main" function when region-checking a function item or a closure
-    /// within a function item. It begins by updating various fields (e.g., `call_site_scope`
-    /// and `outlives_environment`) to be appropriate to the function and then adds constraints
-    /// derived from the function body.
+    /// This is the "main" function when region-checking a function item or a
+    /// closure within a function item. It begins by updating various fields
+    /// (e.g., `outlives_environment`) to be appropriate to the function and
+    /// then adds constraints derived from the function body.
     ///
     /// Note that it does **not** restore the state of the fields that
     /// it updates! This is intentional, since -- for the main
@@ -292,10 +262,6 @@
         self.body_id = body_id.hir_id;
         self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
 
-        let call_site =
-            region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite };
-        self.call_site_scope = Some(call_site);
-
         let fn_sig = {
             match self.tables.borrow().liberated_fn_sigs().get(id) {
                 Some(f) => *f,
@@ -324,12 +290,6 @@
         self.visit_body(body);
         self.visit_region_obligations(body_id.hir_id);
 
-        let call_site_scope = self.call_site_scope.unwrap();
-        debug!("visit_fn_body body.id {:?} call_site_scope: {:?}", body.id(), call_site_scope);
-        let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
-
-        self.type_of_node_must_outlive(infer::CallReturn(span), body_id.hir_id, call_site_region);
-
         self.constrain_opaque_types(
             &self.fcx.opaque_types.borrow(),
             self.outlives_environment.free_region_map(),
@@ -354,7 +314,6 @@
 
         self.fcx.resolve_regions_and_report_errors(
             self.subject_def_id.to_def_id(),
-            &self.region_scope_tree,
             &self.outlives_environment,
             mode,
         );
@@ -363,34 +322,6 @@
     fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat<'_>) {
         debug!("regionck::visit_pat(pat={:?})", pat);
         pat.each_binding(|_, hir_id, span, _| {
-            // If we have a variable that contains region'd data, that
-            // data will be accessible from anywhere that the variable is
-            // accessed. We must be wary of loops like this:
-            //
-            //     // from src/test/compile-fail/borrowck-lend-flow.rs
-            //     let mut v = box 3, w = box 4;
-            //     let mut x = &mut w;
-            //     loop {
-            //         **x += 1;   // (2)
-            //         borrow(v);  //~ ERROR cannot borrow
-            //         x = &mut v; // (1)
-            //     }
-            //
-            // Typically, we try to determine the region of a borrow from
-            // those points where it is dereferenced. In this case, one
-            // might imagine that the lifetime of `x` need only be the
-            // body of the loop. But of course this is incorrect because
-            // the pointer that is created at point (1) is consumed at
-            // point (2), meaning that it must be live across the loop
-            // iteration. The easiest way to guarantee this is to require
-            // that the lifetime of any regions that appear in a
-            // variable's type enclose at least the variable's scope.
-            let var_scope = self.region_scope_tree.var_scope(hir_id.local_id);
-            let var_region = self.tcx.mk_region(ty::ReScope(var_scope));
-
-            let origin = infer::BindingTypeIsNotValidAtDecl(span);
-            self.type_of_node_must_outlive(origin, hir_id, var_region);
-
             let typ = self.resolve_node_type(hir_id);
             let body_id = self.body_id;
             let _ = dropck::check_drop_obligations(self, typ, span, body_id);
@@ -433,7 +364,6 @@
         // `visit_fn_body`.  We will restore afterwards.
         let old_body_id = self.body_id;
         let old_body_owner = self.body_owner;
-        let old_call_site_scope = self.call_site_scope;
         let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
 
         let body = self.tcx.hir().body(body_id);
@@ -441,7 +371,6 @@
 
         // Restore state from previous function.
         self.outlives_environment.pop_snapshot_post_closure(env_snapshot);
-        self.call_site_scope = old_call_site_scope;
         self.body_id = old_body_id;
         self.body_owner = old_body_owner;
     }
@@ -462,42 +391,6 @@
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        debug!("regionck::visit_expr(e={:?}, repeating_scope={:?})", expr, self.repeating_scope);
-
-        // No matter what, the type of each expression must outlive the
-        // scope of that expression. This also guarantees basic WF.
-        let expr_ty = self.resolve_node_type(expr.hir_id);
-        // the region corresponding to this expression
-        let expr_region = self.tcx.mk_region(ty::ReScope(region::Scope {
-            id: expr.hir_id.local_id,
-            data: region::ScopeData::Node,
-        }));
-        self.type_must_outlive(
-            infer::ExprTypeIsNotInScope(expr_ty, expr.span),
-            expr_ty,
-            expr_region,
-        );
-
-        let is_method_call = self.tables.borrow().is_method_call(expr);
-
-        // If we are calling a method (either explicitly or via an
-        // overloaded operator), check that all of the types provided as
-        // arguments for its type parameters are well-formed, and all the regions
-        // provided as arguments outlive the call.
-        if is_method_call {
-            let origin = match expr.kind {
-                hir::ExprKind::MethodCall(..) => infer::ParameterOrigin::MethodCall,
-                hir::ExprKind::Unary(op, _) if op == hir::UnOp::UnDeref => {
-                    infer::ParameterOrigin::OverloadedDeref
-                }
-                _ => infer::ParameterOrigin::OverloadedOperator,
-            };
-
-            let substs = self.tables.borrow().node_substs(expr.hir_id);
-            self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
-            // Arguments (sub-expressions) are checked via `constrain_call`, below.
-        }
-
         // Check any autoderefs or autorefs that appear.
         let cmt_result = self.constrain_adjustments(expr);
 
@@ -512,117 +405,10 @@
             }
         }
 
-        debug!(
-            "regionck::visit_expr(e={:?}, repeating_scope={:?}) - visiting subexprs",
-            expr, self.repeating_scope
-        );
         match expr.kind {
-            hir::ExprKind::Path(_) => {
-                let substs = self.tables.borrow().node_substs(expr.hir_id);
-                let origin = infer::ParameterOrigin::Path;
-                self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
-            }
-
-            hir::ExprKind::Call(ref callee, ref args) => {
-                if is_method_call {
-                    self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e));
-                } else {
-                    self.constrain_callee(&callee);
-                    self.constrain_call(expr, None, args.iter().map(|e| &*e));
-                }
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::MethodCall(.., ref args) => {
-                self.constrain_call(expr, Some(&args[0]), args[1..].iter().map(|e| &*e));
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => {
-                if is_method_call {
-                    self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
-                }
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::Index(ref lhs, ref rhs) if is_method_call => {
-                self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::Binary(_, ref lhs, ref rhs) if is_method_call => {
-                // As `ExprKind::MethodCall`, but the call is via an overloaded op.
-                self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::Binary(_, ref lhs, ref rhs) => {
-                // If you do `x OP y`, then the types of `x` and `y` must
-                // outlive the operation you are performing.
-                let lhs_ty = self.resolve_expr_type_adjusted(&lhs);
-                let rhs_ty = self.resolve_expr_type_adjusted(&rhs);
-                for &ty in &[lhs_ty, rhs_ty] {
-                    self.type_must_outlive(infer::Operand(expr.span), ty, expr_region);
-                }
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base) => {
-                // For *a, the lifetime of a must enclose the deref
-                if is_method_call {
-                    self.constrain_call(expr, Some(base), None::<hir::Expr<'_>>.iter());
-                }
-                // For overloaded derefs, base_ty is the input to `Deref::deref`,
-                // but it's a reference type uing the same region as the output.
-                let base_ty = self.resolve_expr_type_adjusted(base);
-                if let ty::Ref(r_ptr, _, _) = base_ty.kind {
-                    self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr);
-                }
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::Unary(_, ref lhs) if is_method_call => {
-                // As above.
-                self.constrain_call(expr, Some(&lhs), None::<hir::Expr<'_>>.iter());
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::Index(ref vec_expr, _) => {
-                // For a[b], the lifetime of a must enclose the deref
-                let vec_type = self.resolve_expr_type_adjusted(&vec_expr);
-                self.constrain_index(expr, vec_type);
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::Cast(ref source, _) => {
-                // Determine if we are casting `source` to a trait
-                // instance.  If so, we have to be sure that the type of
-                // the source obeys the trait's region bound.
-                self.constrain_cast(expr, &source);
-                intravisit::walk_expr(self, expr);
-            }
-
             hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => {
                 self.link_addr_of(expr, m, &base);
 
-                // Require that when you write a `&expr` expression, the
-                // resulting pointer has a lifetime that encompasses the
-                // `&expr` expression itself. Note that we constraining
-                // the type of the node expr.id here *before applying
-                // adjustments*.
-                //
-                // FIXME(https://github.com/rust-lang/rfcs/issues/811)
-                // nested method calls requires that this rule change
-                let ty0 = self.resolve_node_type(expr.hir_id);
-                self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region);
                 intravisit::walk_expr(self, expr);
             }
 
@@ -632,140 +418,12 @@
                 intravisit::walk_expr(self, expr);
             }
 
-            hir::ExprKind::Closure(.., body_id, _, _) => {
-                self.check_expr_fn_block(expr, body_id);
-            }
-
-            hir::ExprKind::Loop(ref body, _, _) => {
-                let repeating_scope = self.set_repeating_scope(body.hir_id);
-                intravisit::walk_expr(self, expr);
-                self.set_repeating_scope(repeating_scope);
-            }
-
-            hir::ExprKind::Ret(Some(ref ret_expr)) => {
-                let call_site_scope = self.call_site_scope;
-                debug!(
-                    "visit_expr ExprKind::Ret ret_expr.hir_id {} call_site_scope: {:?}",
-                    ret_expr.hir_id, call_site_scope
-                );
-                let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope.unwrap()));
-                self.type_of_node_must_outlive(
-                    infer::CallReturn(ret_expr.span),
-                    ret_expr.hir_id,
-                    call_site_region,
-                );
-                intravisit::walk_expr(self, expr);
-            }
-
-            _ => {
-                intravisit::walk_expr(self, expr);
-            }
+            _ => intravisit::walk_expr(self, expr),
         }
     }
 }
 
 impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
-    fn constrain_cast(&mut self, cast_expr: &hir::Expr<'_>, source_expr: &hir::Expr<'_>) {
-        debug!("constrain_cast(cast_expr={:?}, source_expr={:?})", cast_expr, source_expr);
-
-        let source_ty = self.resolve_node_type(source_expr.hir_id);
-        let target_ty = self.resolve_node_type(cast_expr.hir_id);
-
-        self.walk_cast(cast_expr, source_ty, target_ty);
-    }
-
-    fn walk_cast(&mut self, cast_expr: &hir::Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) {
-        debug!("walk_cast(from_ty={:?}, to_ty={:?})", from_ty, to_ty);
-        match (&from_ty.kind, &to_ty.kind) {
-            /*From:*/
-            (&ty::Ref(from_r, from_ty, _), /*To:  */ &ty::Ref(to_r, to_ty, _)) => {
-                // Target cannot outlive source, naturally.
-                self.sub_regions(infer::Reborrow(cast_expr.span), to_r, from_r);
-                self.walk_cast(cast_expr, from_ty, to_ty);
-            }
-
-            /*From:*/
-            (_, /*To:  */ &ty::Dynamic(.., r)) => {
-                // When T is existentially quantified as a trait
-                // `Foo+'to`, it must outlive the region bound `'to`.
-                self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), from_ty, r);
-            }
-
-            /*From:*/
-            (&ty::Adt(from_def, _), /*To:  */ &ty::Adt(to_def, _))
-                if from_def.is_box() && to_def.is_box() =>
-            {
-                self.walk_cast(cast_expr, from_ty.boxed_ty(), to_ty.boxed_ty());
-            }
-
-            _ => {}
-        }
-    }
-
-    fn check_expr_fn_block(&mut self, expr: &'tcx hir::Expr<'tcx>, body_id: hir::BodyId) {
-        let repeating_scope = self.set_repeating_scope(body_id.hir_id);
-        intravisit::walk_expr(self, expr);
-        self.set_repeating_scope(repeating_scope);
-    }
-
-    fn constrain_callee(&mut self, callee_expr: &hir::Expr<'_>) {
-        let callee_ty = self.resolve_node_type(callee_expr.hir_id);
-        match callee_ty.kind {
-            ty::FnDef(..) | ty::FnPtr(_) => {}
-            _ => {
-                // this should not happen, but it does if the program is
-                // erroneous
-                //
-                // bug!(
-                //     callee_expr.span,
-                //     "Calling non-function: {}",
-                //     callee_ty);
-            }
-        }
-    }
-
-    fn constrain_call<'b, I: Iterator<Item = &'b hir::Expr<'b>>>(
-        &mut self,
-        call_expr: &hir::Expr<'_>,
-        receiver: Option<&hir::Expr<'_>>,
-        arg_exprs: I,
-    ) {
-        //! Invoked on every call site (i.e., normal calls, method calls,
-        //! and overloaded operators). Constrains the regions which appear
-        //! in the type of the function. Also constrains the regions that
-        //! appear in the arguments appropriately.
-
-        debug!("constrain_call(call_expr={:?}, receiver={:?})", call_expr, receiver);
-
-        // `callee_region` is the scope representing the time in which the
-        // call occurs.
-        //
-        // FIXME(#6268) to support nested method calls, should be callee_id
-        let callee_scope =
-            region::Scope { id: call_expr.hir_id.local_id, data: region::ScopeData::Node };
-        let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope));
-
-        debug!("callee_region={:?}", callee_region);
-
-        for arg_expr in arg_exprs {
-            debug!("argument: {:?}", arg_expr);
-
-            // ensure that any regions appearing in the argument type are
-            // valid for at least the lifetime of the function:
-            self.type_of_node_must_outlive(
-                infer::CallArg(arg_expr.span),
-                arg_expr.hir_id,
-                callee_region,
-            );
-        }
-
-        // as loop above, but for receiver
-        if let Some(r) = receiver {
-            debug!("receiver: {:?}", r);
-            self.type_of_node_must_outlive(infer::CallRcvr(r.span), r.hir_id, callee_region);
-        }
-    }
-
     /// Creates a temporary `MemCategorizationContext` and pass it to the closure.
     fn with_mc<F, R>(&self, f: F) -> R
     where
@@ -784,79 +442,40 @@
     fn constrain_adjustments(&mut self, expr: &hir::Expr<'_>) -> mc::McResult<mc::Place<'tcx>> {
         debug!("constrain_adjustments(expr={:?})", expr);
 
-        let mut cmt = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
+        let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
 
         let tables = self.tables.borrow();
         let adjustments = tables.expr_adjustments(&expr);
         if adjustments.is_empty() {
-            return Ok(cmt);
+            return Ok(place);
         }
 
         debug!("constrain_adjustments: adjustments={:?}", adjustments);
 
         // If necessary, constrain destructors in the unadjusted form of this
         // expression.
-        self.check_safety_of_rvalue_destructor_if_necessary(&cmt, expr.span);
+        self.check_safety_of_rvalue_destructor_if_necessary(&place, expr.span);
 
-        let expr_region = self.tcx.mk_region(ty::ReScope(region::Scope {
-            id: expr.hir_id.local_id,
-            data: region::ScopeData::Node,
-        }));
         for adjustment in adjustments {
-            debug!("constrain_adjustments: adjustment={:?}, cmt={:?}", adjustment, cmt);
+            debug!("constrain_adjustments: adjustment={:?}, place={:?}", adjustment, place);
 
             if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind {
-                debug!("constrain_adjustments: overloaded deref: {:?}", deref);
-
-                // Treat overloaded autoderefs as if an AutoBorrow adjustment
-                // was applied on the base type, as that is always the case.
-                let input = self
-                    .tcx
-                    .mk_ref(deref.region, ty::TypeAndMut { ty: cmt.ty, mutbl: deref.mutbl });
-                let output = self.tcx.mk_ref(
-                    deref.region,
-                    ty::TypeAndMut { ty: adjustment.target, mutbl: deref.mutbl },
-                );
-
                 self.link_region(
                     expr.span,
                     deref.region,
                     ty::BorrowKind::from_mutbl(deref.mutbl),
-                    &cmt,
+                    &place,
                 );
-
-                // Specialized version of constrain_call.
-                self.type_must_outlive(infer::CallRcvr(expr.span), input, expr_region);
-                self.type_must_outlive(infer::CallReturn(expr.span), output, expr_region);
             }
 
             if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind {
-                self.link_autoref(expr, &cmt, autoref);
-
-                // Require that the resulting region encompasses
-                // the current node.
-                //
-                // FIXME(#6268) remove to support nested method calls
-                self.type_of_node_must_outlive(
-                    infer::AutoBorrow(expr.span),
-                    expr.hir_id,
-                    expr_region,
-                );
+                self.link_autoref(expr, &place, autoref);
             }
 
-            cmt = self.with_mc(|mc| mc.cat_expr_adjusted(expr, cmt, &adjustment))?;
+            place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, &adjustment))?;
         }
 
-        Ok(cmt)
-    }
-
-    pub fn mk_subregion_due_to_dereference(
-        &mut self,
-        deref_span: Span,
-        minimum_lifetime: ty::Region<'tcx>,
-        maximum_lifetime: ty::Region<'tcx>,
-    ) {
-        self.sub_regions(infer::DerefPointer(deref_span), minimum_lifetime, maximum_lifetime)
+        Ok(place)
     }
 
     fn check_safety_of_rvalue_destructor_if_necessary(
@@ -872,59 +491,6 @@
             }
         }
     }
-
-    /// Invoked on any index expression that occurs. Checks that if this is a slice
-    /// being indexed, the lifetime of the pointer includes the deref expr.
-    fn constrain_index(&mut self, index_expr: &hir::Expr<'_>, indexed_ty: Ty<'tcx>) {
-        debug!("constrain_index(index_expr=?, indexed_ty={}", self.ty_to_string(indexed_ty));
-
-        let r_index_expr = ty::ReScope(region::Scope {
-            id: index_expr.hir_id.local_id,
-            data: region::ScopeData::Node,
-        });
-        if let ty::Ref(r_ptr, r_ty, _) = indexed_ty.kind {
-            match r_ty.kind {
-                ty::Slice(_) | ty::Str => {
-                    self.sub_regions(
-                        infer::IndexSlice(index_expr.span),
-                        self.tcx.mk_region(r_index_expr),
-                        r_ptr,
-                    );
-                }
-                _ => {}
-            }
-        }
-    }
-
-    /// Guarantees that any lifetimes that appear in the type of the node `id` (after applying
-    /// adjustments) are valid for at least `minimum_lifetime`.
-    fn type_of_node_must_outlive(
-        &mut self,
-        origin: infer::SubregionOrigin<'tcx>,
-        hir_id: hir::HirId,
-        minimum_lifetime: ty::Region<'tcx>,
-    ) {
-        // Try to resolve the type.  If we encounter an error, then typeck
-        // is going to fail anyway, so just stop here and let typeck
-        // report errors later on in the writeback phase.
-        let ty0 = self.resolve_node_type(hir_id);
-
-        let ty = self
-            .tables
-            .borrow()
-            .adjustments()
-            .get(hir_id)
-            .and_then(|adj| adj.last())
-            .map_or(ty0, |adj| adj.target);
-        let ty = self.resolve_type(ty);
-        debug!(
-            "constrain_regions_in_type_of_node(\
-             ty={}, ty0={}, id={:?}, minimum_lifetime={:?})",
-            ty, ty0, hir_id, minimum_lifetime
-        );
-        self.type_must_outlive(origin, ty, minimum_lifetime);
-    }
-
     /// Adds constraints to inference such that `T: 'a` holds (or
     /// reports an error if it cannot).
     ///
@@ -1035,13 +601,7 @@
                 self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m.into()), expr_cmt);
             }
 
-            adjustment::AutoBorrow::RawPtr(m) => {
-                let r = self.tcx.mk_region(ty::ReScope(region::Scope {
-                    id: expr.hir_id.local_id,
-                    data: region::ScopeData::Node,
-                }));
-                self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
-            }
+            adjustment::AutoBorrow::RawPtr(_) => {}
         }
     }
 
@@ -1251,39 +811,4 @@
             }
         }
     }
-
-    /// Checks that the values provided for type/region arguments in a given
-    /// expression are well-formed and in-scope.
-    fn substs_wf_in_scope(
-        &mut self,
-        origin: infer::ParameterOrigin,
-        substs: SubstsRef<'tcx>,
-        expr_span: Span,
-        expr_region: ty::Region<'tcx>,
-    ) {
-        debug!(
-            "substs_wf_in_scope(substs={:?}, \
-             expr_region={:?}, \
-             origin={:?}, \
-             expr_span={:?})",
-            substs, expr_region, origin, expr_span
-        );
-
-        let origin = infer::ParameterInScope(origin, expr_span);
-
-        for kind in substs {
-            match kind.unpack() {
-                GenericArgKind::Lifetime(lt) => {
-                    self.sub_regions(origin.clone(), expr_region, lt);
-                }
-                GenericArgKind::Type(ty) => {
-                    let ty = self.resolve_type(ty);
-                    self.type_must_outlive(origin.clone(), ty, expr_region);
-                }
-                GenericArgKind::Const(_) => {
-                    // Const parameters don't impose constraints.
-                }
-            }
-        }
-    }
 }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index b79ac50..d5db613 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -425,7 +425,8 @@
                 fcx.register_predicate(traits::Obligation::new(
                     cause,
                     fcx.param_env,
-                    ty::Predicate::ConstEvaluatable(discr_def_id.to_def_id(), discr_substs),
+                    ty::PredicateKind::ConstEvaluatable(discr_def_id.to_def_id(), discr_substs)
+                        .to_predicate(fcx.tcx),
                 ));
             }
         }
@@ -1174,8 +1175,11 @@
         substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
     };
 
-    let obligation =
-        traits::Obligation::new(cause, fcx.param_env, trait_ref.without_const().to_predicate());
+    let obligation = traits::Obligation::new(
+        cause,
+        fcx.param_env,
+        trait_ref.without_const().to_predicate(fcx.tcx),
+    );
 
     if fcx.predicate_must_hold_modulo_regions(&obligation) {
         true
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index efa3cd9..c5dd314 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -11,7 +11,6 @@
 use rustc_infer::infer;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionckMode, TyCtxtInferExt};
-use rustc_middle::middle::region;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -293,11 +292,9 @@
                     }
 
                     // Finally, resolve all regions.
-                    let region_scope_tree = region::ScopeTree::default();
                     let outlives_env = OutlivesEnvironment::new(param_env);
                     infcx.resolve_regions_and_report_errors(
                         impl_did.to_def_id(),
-                        &region_scope_tree,
                         &outlives_env,
                         RegionckMode::default(),
                     );
@@ -552,14 +549,8 @@
         }
 
         // Finally, resolve all regions.
-        let region_scope_tree = region::ScopeTree::default();
         let outlives_env = OutlivesEnvironment::new(param_env);
-        infcx.resolve_regions_and_report_errors(
-            impl_did,
-            &region_scope_tree,
-            &outlives_env,
-            RegionckMode::default(),
-        );
+        infcx.resolve_regions_and_report_errors(impl_did, &outlives_env, RegionckMode::default());
 
         CoerceUnsizedInfo { custom_kind: kind }
     })
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 66ef6a0..355b4fc 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -528,7 +528,7 @@
                     if param_id == item_hir_id {
                         let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
                         extend =
-                            Some((identity_trait_ref.without_const().to_predicate(), item.span));
+                            Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
                     }
                     generics
                 }
@@ -548,8 +548,10 @@
     let extra_predicates = extend.into_iter().chain(
         icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))
             .into_iter()
-            .filter(|(predicate, _)| match predicate {
-                ty::Predicate::Trait(ref data, _) => data.skip_binder().self_ty().is_param(index),
+            .filter(|(predicate, _)| match predicate.kind() {
+                ty::PredicateKind::Trait(ref data, _) => {
+                    data.skip_binder().self_ty().is_param(index)
+                }
                 _ => false,
             }),
     );
@@ -994,7 +996,7 @@
     // which will, in turn, reach indirect supertraits.
     for &(pred, span) in superbounds {
         debug!("superbound: {:?}", pred);
-        if let ty::Predicate::Trait(bound, _) = pred {
+        if let ty::PredicateKind::Trait(bound, _) = pred.kind() {
             tcx.at(span).super_predicates_of(bound.def_id());
         }
     }
@@ -1655,7 +1657,7 @@
         let span = tcx.sess.source_map().guess_head_span(tcx.def_span(def_id));
         result.predicates =
             tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
-                ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(),
+                ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(tcx),
                 span,
             ))));
     }
@@ -1830,7 +1832,7 @@
     // set of defaults that can be incorporated into another impl.
     if let Some(trait_ref) = is_default_impl_trait {
         predicates.push((
-            trait_ref.to_poly_trait_ref().without_const().to_predicate(),
+            trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx),
             tcx.def_span(def_id),
         ));
     }
@@ -1853,7 +1855,7 @@
                     hir::GenericBound::Outlives(lt) => {
                         let bound = AstConv::ast_region_to_region(&icx, &lt, None);
                         let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound));
-                        predicates.push((outlives.to_predicate(), lt.span));
+                        predicates.push((outlives.to_predicate(tcx), lt.span));
                     }
                     _ => bug!(),
                 });
@@ -1899,7 +1901,8 @@
                         let re_root_empty = tcx.lifetimes.re_root_empty;
                         let predicate = ty::OutlivesPredicate(ty, re_root_empty);
                         predicates.push((
-                            ty::Predicate::TypeOutlives(ty::Binder::dummy(predicate)),
+                            ty::PredicateKind::TypeOutlives(ty::Binder::dummy(predicate))
+                                .to_predicate(tcx),
                             span,
                         ));
                     }
@@ -1928,7 +1931,10 @@
                         &hir::GenericBound::Outlives(ref lifetime) => {
                             let region = AstConv::ast_region_to_region(&icx, lifetime, None);
                             let pred = ty::Binder::bind(ty::OutlivesPredicate(ty, region));
-                            predicates.push((ty::Predicate::TypeOutlives(pred), lifetime.span))
+                            predicates.push((
+                                ty::PredicateKind::TypeOutlives(pred).to_predicate(tcx),
+                                lifetime.span,
+                            ))
                         }
                     }
                 }
@@ -1945,7 +1951,7 @@
                     };
                     let pred = ty::Binder::bind(ty::OutlivesPredicate(r1, r2));
 
-                    (ty::Predicate::RegionOutlives(pred), span)
+                    (ty::PredicateKind::RegionOutlives(pred).to_predicate(icx.tcx), span)
                 }))
             }
 
@@ -2116,7 +2122,7 @@
         hir::GenericBound::Outlives(ref lifetime) => {
             let region = astconv.ast_region_to_region(lifetime, None);
             let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region));
-            vec![(ty::Predicate::TypeOutlives(pred), lifetime.span)]
+            vec![(ty::PredicateKind::TypeOutlives(pred).to_predicate(astconv.tcx()), lifetime.span)]
         }
     }
 }
diff --git a/src/librustc_typeck/constrained_generic_params.rs b/src/librustc_typeck/constrained_generic_params.rs
index 07ff3bc..34497d1 100644
--- a/src/librustc_typeck/constrained_generic_params.rs
+++ b/src/librustc_typeck/constrained_generic_params.rs
@@ -180,7 +180,7 @@
         changed = false;
 
         for j in i..predicates.len() {
-            if let ty::Predicate::Projection(ref poly_projection) = predicates[j].0 {
+            if let ty::PredicateKind::Projection(ref poly_projection) = predicates[j].0.kind() {
                 // Note that we can skip binder here because the impl
                 // trait ref never contains any late-bound regions.
                 let projection = poly_projection.skip_binder();
diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs
index 919bcc9..08404be 100644
--- a/src/librustc_typeck/impl_wf_check/min_specialization.rs
+++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs
@@ -73,7 +73,6 @@
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
 use rustc_infer::traits::specialization_graph::Node;
-use rustc_middle::middle::region::ScopeTree;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable};
@@ -165,12 +164,7 @@
 
     // Conservatively use an empty `ParamEnv`.
     let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
-    infcx.resolve_regions_and_report_errors(
-        impl1_def_id,
-        &ScopeTree::default(),
-        &outlives_env,
-        RegionckMode::default(),
-    );
+    infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env, RegionckMode::default());
     let impl2_substs = match infcx.fully_resolve(&impl2_substs) {
         Ok(s) => s,
         Err(_) => {
@@ -204,7 +198,7 @@
     // the functions in `cgp` add the constrained parameters to a list of
     // unconstrained parameters.
     for (predicate, _) in impl_generic_predicates.predicates.iter() {
-        if let ty::Predicate::Projection(proj) = predicate {
+        if let ty::PredicateKind::Projection(proj) = predicate.kind() {
             let projection_ty = proj.skip_binder().projection_ty;
             let projected_ty = proj.skip_binder().ty;
 
@@ -368,13 +362,13 @@
 
 fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: &ty::Predicate<'tcx>, span: Span) {
     debug!("can_specialize_on(predicate = {:?})", predicate);
-    match predicate {
+    match predicate.kind() {
         // Global predicates are either always true or always false, so we
         // are fine to specialize on.
         _ if predicate.is_global() => (),
         // We allow specializing on explicitly marked traits with no associated
         // items.
-        ty::Predicate::Trait(pred, hir::Constness::NotConst) => {
+        ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
             if !matches!(
                 trait_predicate_kind(tcx, predicate),
                 Some(TraitSpecializationKind::Marker)
@@ -401,19 +395,19 @@
     tcx: TyCtxt<'tcx>,
     predicate: &ty::Predicate<'tcx>,
 ) -> Option<TraitSpecializationKind> {
-    match predicate {
-        ty::Predicate::Trait(pred, hir::Constness::NotConst) => {
+    match predicate.kind() {
+        ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
             Some(tcx.trait_def(pred.def_id()).specialization_kind)
         }
-        ty::Predicate::Trait(_, hir::Constness::Const)
-        | ty::Predicate::RegionOutlives(_)
-        | ty::Predicate::TypeOutlives(_)
-        | ty::Predicate::Projection(_)
-        | ty::Predicate::WellFormed(_)
-        | ty::Predicate::Subtype(_)
-        | ty::Predicate::ObjectSafe(_)
-        | ty::Predicate::ClosureKind(..)
-        | ty::Predicate::ConstEvaluatable(..)
-        | ty::Predicate::ConstEquate(..) => None,
+        ty::PredicateKind::Trait(_, hir::Constness::Const)
+        | ty::PredicateKind::RegionOutlives(_)
+        | ty::PredicateKind::TypeOutlives(_)
+        | ty::PredicateKind::Projection(_)
+        | ty::PredicateKind::WellFormed(_)
+        | ty::PredicateKind::Subtype(_)
+        | ty::PredicateKind::ObjectSafe(_)
+        | ty::PredicateKind::ClosureKind(..)
+        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::ConstEquate(..) => None,
     }
 }
diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs
index 66daf0e..5740cc2 100644
--- a/src/librustc_typeck/outlives/explicit.rs
+++ b/src/librustc_typeck/outlives/explicit.rs
@@ -29,8 +29,8 @@
 
             // process predicates and convert to `RequiredPredicates` entry, see below
             for &(predicate, span) in predicates.predicates {
-                match predicate {
-                    ty::Predicate::TypeOutlives(predicate) => {
+                match predicate.kind() {
+                    ty::PredicateKind::TypeOutlives(predicate) => {
                         let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder();
                         insert_outlives_predicate(
                             tcx,
@@ -41,7 +41,7 @@
                         )
                     }
 
-                    ty::Predicate::RegionOutlives(predicate) => {
+                    ty::PredicateKind::RegionOutlives(predicate) => {
                         let OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder();
                         insert_outlives_predicate(
                             tcx,
@@ -52,14 +52,14 @@
                         )
                     }
 
-                    ty::Predicate::Trait(..)
-                    | ty::Predicate::Projection(..)
-                    | ty::Predicate::WellFormed(..)
-                    | ty::Predicate::ObjectSafe(..)
-                    | ty::Predicate::ClosureKind(..)
-                    | ty::Predicate::Subtype(..)
-                    | ty::Predicate::ConstEvaluatable(..)
-                    | ty::Predicate::ConstEquate(..) => (),
+                    ty::PredicateKind::Trait(..)
+                    | ty::PredicateKind::Projection(..)
+                    | ty::PredicateKind::WellFormed(..)
+                    | ty::PredicateKind::ObjectSafe(..)
+                    | ty::PredicateKind::ClosureKind(..)
+                    | ty::PredicateKind::Subtype(..)
+                    | ty::PredicateKind::ConstEvaluatable(..)
+                    | ty::PredicateKind::ConstEquate(..) => (),
                 }
             }
 
diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs
index a49d8e5..1b2b08a 100644
--- a/src/librustc_typeck/outlives/mod.rs
+++ b/src/librustc_typeck/outlives/mod.rs
@@ -3,7 +3,7 @@
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt};
+use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
@@ -30,9 +30,9 @@
                 if tcx.has_attr(item_def_id, sym::rustc_outlives) {
                     let mut pred: Vec<String> = predicates
                         .iter()
-                        .map(|(out_pred, _)| match out_pred {
-                            ty::Predicate::RegionOutlives(p) => p.to_string(),
-                            ty::Predicate::TypeOutlives(p) => p.to_string(),
+                        .map(|(out_pred, _)| match out_pred.kind() {
+                            ty::PredicateKind::RegionOutlives(p) => p.to_string(),
+                            ty::PredicateKind::TypeOutlives(p) => p.to_string(),
                             err => bug!("unexpected predicate {:?}", err),
                         })
                         .collect();
@@ -82,22 +82,26 @@
         .iter()
         .map(|(&def_id, set)| {
             let predicates = &*tcx.arena.alloc_from_iter(set.iter().filter_map(
-                |(ty::OutlivesPredicate(kind1, region2), &span)| match kind1.unpack() {
-                    GenericArgKind::Type(ty1) => Some((
-                        ty::Predicate::TypeOutlives(ty::Binder::bind(ty::OutlivesPredicate(
-                            ty1, region2,
-                        ))),
-                        span,
-                    )),
-                    GenericArgKind::Lifetime(region1) => Some((
-                        ty::Predicate::RegionOutlives(ty::Binder::bind(ty::OutlivesPredicate(
-                            region1, region2,
-                        ))),
-                        span,
-                    )),
-                    GenericArgKind::Const(_) => {
-                        // Generic consts don't impose any constraints.
-                        None
+                |(ty::OutlivesPredicate(kind1, region2), &span)| {
+                    match kind1.unpack() {
+                        GenericArgKind::Type(ty1) => Some((
+                            ty::PredicateKind::TypeOutlives(ty::Binder::bind(
+                                ty::OutlivesPredicate(ty1, region2),
+                            ))
+                            .to_predicate(tcx),
+                            span,
+                        )),
+                        GenericArgKind::Lifetime(region1) => Some((
+                            ty::PredicateKind::RegionOutlives(ty::Binder::bind(
+                                ty::OutlivesPredicate(region1, region2),
+                            ))
+                            .to_predicate(tcx),
+                            span,
+                        )),
+                        GenericArgKind::Const(_) => {
+                            // Generic consts don't impose any constraints.
+                            None
+                        }
                     }
                 },
             ));
diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs
index 3bbe3e3..8b06967 100644
--- a/src/librustc_typeck/outlives/utils.rs
+++ b/src/librustc_typeck/outlives/utils.rs
@@ -170,7 +170,6 @@
 
         // These regions don't appear in types from type declarations:
         RegionKind::ReErased
-        | RegionKind::ReScope(..)
         | RegionKind::ReVar(..)
         | RegionKind::RePlaceholder(..)
         | RegionKind::ReFree(..) => {
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 3a680f5..e04af68 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -444,7 +444,6 @@
             }
 
             ty::ReFree(..)
-            | ty::ReScope(..)
             | ty::ReVar(..)
             | ty::RePlaceholder(..)
             | ty::ReEmpty(_)
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 144c169..423160f 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -315,11 +315,11 @@
         tcx: TyCtxt<'tcx>,
         pred: ty::Predicate<'tcx>,
     ) -> FxHashSet<GenericParamDef> {
-        let regions = match pred {
-            ty::Predicate::Trait(poly_trait_pred, _) => {
+        let regions = match pred.kind() {
+            ty::PredicateKind::Trait(poly_trait_pred, _) => {
                 tcx.collect_referenced_late_bound_regions(&poly_trait_pred)
             }
-            ty::Predicate::Projection(poly_proj_pred) => {
+            ty::PredicateKind::Projection(poly_proj_pred) => {
                 tcx.collect_referenced_late_bound_regions(&poly_proj_pred)
             }
             _ => return FxHashSet::default(),
@@ -465,8 +465,8 @@
             .iter()
             .filter(|p| {
                 !orig_bounds.contains(p)
-                    || match p {
-                        ty::Predicate::Trait(pred, _) => pred.def_id() == sized_trait,
+                    || match p.kind() {
+                        ty::PredicateKind::Trait(pred, _) => pred.def_id() == sized_trait,
                         _ => false,
                     }
             })
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index d987505..3d27855 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -65,7 +65,7 @@
                         match infcx.evaluate_obligation(&traits::Obligation::new(
                             cause,
                             param_env,
-                            trait_ref.without_const().to_predicate(),
+                            trait_ref.without_const().to_predicate(infcx.tcx),
                         )) {
                             Ok(eval_result) => eval_result.may_apply(),
                             Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c130ed3..702c7d1 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -447,7 +447,6 @@
 
             ty::ReLateBound(..)
             | ty::ReFree(..)
-            | ty::ReScope(..)
             | ty::ReVar(..)
             | ty::RePlaceholder(..)
             | ty::ReEmpty(_)
@@ -481,20 +480,18 @@
 
 impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
     fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
-        use rustc_middle::ty::Predicate;
+        match self.kind() {
+            ty::PredicateKind::Trait(ref pred, _) => Some(pred.clean(cx)),
+            ty::PredicateKind::Subtype(ref pred) => Some(pred.clean(cx)),
+            ty::PredicateKind::RegionOutlives(ref pred) => pred.clean(cx),
+            ty::PredicateKind::TypeOutlives(ref pred) => pred.clean(cx),
+            ty::PredicateKind::Projection(ref pred) => Some(pred.clean(cx)),
 
-        match *self {
-            Predicate::Trait(ref pred, _) => Some(pred.clean(cx)),
-            Predicate::Subtype(ref pred) => Some(pred.clean(cx)),
-            Predicate::RegionOutlives(ref pred) => pred.clean(cx),
-            Predicate::TypeOutlives(ref pred) => pred.clean(cx),
-            Predicate::Projection(ref pred) => Some(pred.clean(cx)),
-
-            Predicate::WellFormed(..)
-            | Predicate::ObjectSafe(..)
-            | Predicate::ClosureKind(..)
-            | Predicate::ConstEvaluatable(..)
-            | Predicate::ConstEquate(..) => panic!("not user writable"),
+            ty::PredicateKind::WellFormed(..)
+            | ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..) => panic!("not user writable"),
         }
     }
 }
@@ -765,7 +762,7 @@
                         if let ty::Param(param) = outlives.skip_binder().0.kind {
                             return Some(param.index);
                         }
-                    } else if let ty::Predicate::Projection(p) = p {
+                    } else if let ty::PredicateKind::Projection(p) = p.kind() {
                         if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().kind {
                             projection = Some(p);
                             return Some(param.index);
@@ -1663,7 +1660,7 @@
                     .filter_map(|predicate| {
                         let trait_ref = if let Some(tr) = predicate.to_opt_poly_trait_ref() {
                             tr
-                        } else if let ty::Predicate::TypeOutlives(pred) = *predicate {
+                        } else if let ty::PredicateKind::TypeOutlives(pred) = predicate.kind() {
                             // these should turn up at the end
                             if let Some(r) = pred.skip_binder().1.clean(cx) {
                                 regions.push(GenericBound::Outlives(r));
@@ -1684,7 +1681,7 @@
                             .predicates
                             .iter()
                             .filter_map(|pred| {
-                                if let ty::Predicate::Projection(proj) = *pred {
+                                if let ty::PredicateKind::Projection(proj) = pred.kind() {
                                     let proj = proj.skip_binder();
                                     if proj.projection_ty.trait_ref(cx.tcx)
                                         == *trait_ref.skip_binder()
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 1404d45..37c613f 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -141,7 +141,7 @@
         .predicates
         .iter()
         .filter_map(|(pred, _)| {
-            if let ty::Predicate::Trait(ref pred, _) = *pred {
+            if let ty::PredicateKind::Trait(ref pred, _) = pred.kind() {
                 if pred.skip_binder().trait_ref.self_ty() == self_ty {
                     Some(pred.def_id())
                 } else {
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index ab52475..b1e0ab9 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -3,12 +3,14 @@
 	font-family: 'Fira Sans';
 	font-style: normal;
 	font-weight: 400;
+	font-display: optional;
 	src: local('Fira Sans'), url("FiraSans-Regular.woff") format('woff');
 }
 @font-face {
 	font-family: 'Fira Sans';
 	font-style: normal;
 	font-weight: 500;
+	font-display: optional;
 	src: local('Fira Sans Medium'), url("FiraSans-Medium.woff") format('woff');
 }
 
@@ -17,18 +19,23 @@
 	font-family: 'Source Serif Pro';
 	font-style: normal;
 	font-weight: 400;
+	/* The difference for body text without this font is greater than other fonts,
+	 * so the 0~100ms block of fallback is preferred over optional, for legibility. */
+	font-display: fallback;
 	src: local('Source Serif Pro'), url("SourceSerifPro-Regular.ttf.woff") format('woff');
 }
 @font-face {
 	font-family: 'Source Serif Pro';
 	font-style: italic;
 	font-weight: 400;
+	font-display: optional;
 	src: local('Source Serif Pro Italic'), url("SourceSerifPro-It.ttf.woff") format('woff');
 }
 @font-face {
 	font-family: 'Source Serif Pro';
 	font-style: normal;
 	font-weight: 700;
+	font-display: optional;
 	src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.ttf.woff") format('woff');
 }
 
@@ -37,6 +44,7 @@
 	font-family: 'Source Code Pro';
 	font-style: normal;
 	font-weight: 400;
+	font-display: optional;
 	/* Avoid using locally installed font because bad versions are in circulation:
 	 * see https://github.com/rust-lang/rust/issues/24355 */
 	src: url("SourceCodePro-Regular.woff") format('woff');
@@ -45,6 +53,7 @@
 	font-family: 'Source Code Pro';
 	font-style: normal;
 	font-weight: 600;
+	font-display: optional;
 	src: url("SourceCodePro-Semibold.woff") format('woff');
 }
 
@@ -625,7 +634,7 @@
 	display: initial;
 }
 
-.in-band:hover > .anchor {
+.in-band:hover > .anchor, .impl:hover > .anchor {
 	display: inline-block;
 	position: absolute;
 }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index a3ef350..adb7fc3 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -232,37 +232,46 @@
                     DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias,
                     did,
                 ) => {
-                    // We need item's parent to know if it's
-                    // trait impl or struct/enum/etc impl
-                    let item_parent = item_opt
+                    // Checks if item_name belongs to `impl SomeItem`
+                    let impl_item = cx
+                        .tcx
+                        .inherent_impls(did)
+                        .iter()
+                        .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order())
+                        .find(|item| item.ident.name == item_name);
+                    let trait_item = item_opt
                         .and_then(|item| self.cx.as_local_hir_id(item.def_id))
                         .and_then(|item_hir| {
+                            // Checks if item_name belongs to `impl SomeTrait for SomeItem`
                             let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir);
-                            self.cx.tcx.hir().find(parent_hir)
+                            let item_parent = self.cx.tcx.hir().find(parent_hir);
+                            match item_parent {
+                                Some(hir::Node::Item(hir::Item {
+                                    kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. },
+                                    ..
+                                })) => cx
+                                    .tcx
+                                    .associated_item_def_ids(self_ty.hir_id.owner)
+                                    .iter()
+                                    .map(|child| {
+                                        let associated_item = cx.tcx.associated_item(*child);
+                                        associated_item
+                                    })
+                                    .find(|child| child.ident.name == item_name),
+                                _ => None,
+                            }
                         });
-                    let item = match item_parent {
-                        Some(hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. },
-                            ..
-                        })) => {
-                            // trait impl
-                            cx.tcx
-                                .associated_item_def_ids(self_ty.hir_id.owner)
-                                .iter()
-                                .map(|child| {
-                                    let associated_item = cx.tcx.associated_item(*child);
-                                    associated_item
-                                })
-                                .find(|child| child.ident.name == item_name)
+                    let item = match (impl_item, trait_item) {
+                        (Some(from_impl), Some(_)) => {
+                            // Although it's ambiguous, return impl version for compat. sake.
+                            // To handle that properly resolve() would have to support
+                            // something like
+                            // [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
+                            Some(from_impl)
                         }
-                        _ => {
-                            // struct/enum/etc. impl
-                            cx.tcx
-                                .inherent_impls(did)
-                                .iter()
-                                .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order())
-                                .find(|item| item.ident.name == item_name)
-                        }
+                        (None, Some(from_trait)) => Some(from_trait),
+                        (Some(from_impl), None) => Some(from_impl),
+                        _ => None,
                     };
 
                     if let Some(item) = item {
@@ -422,6 +431,43 @@
 
         look_for_tests(&cx, &dox, &item, true);
 
+        // find item's parent to resolve `Self` in item's docs below
+        let parent_name = self.cx.as_local_hir_id(item.def_id).and_then(|item_hir| {
+            let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir);
+            let item_parent = self.cx.tcx.hir().find(parent_hir);
+            match item_parent {
+                Some(hir::Node::Item(hir::Item {
+                    kind:
+                        hir::ItemKind::Impl {
+                            self_ty:
+                                hir::Ty {
+                                    kind:
+                                        hir::TyKind::Path(hir::QPath::Resolved(
+                                            _,
+                                            hir::Path { segments, .. },
+                                        )),
+                                    ..
+                                },
+                            ..
+                        },
+                    ..
+                })) => segments.first().and_then(|seg| Some(seg.ident.to_string())),
+                Some(hir::Node::Item(hir::Item {
+                    ident, kind: hir::ItemKind::Enum(..), ..
+                }))
+                | Some(hir::Node::Item(hir::Item {
+                    ident, kind: hir::ItemKind::Struct(..), ..
+                }))
+                | Some(hir::Node::Item(hir::Item {
+                    ident, kind: hir::ItemKind::Union(..), ..
+                }))
+                | Some(hir::Node::Item(hir::Item {
+                    ident, kind: hir::ItemKind::Trait(..), ..
+                })) => Some(ident.to_string()),
+                _ => None,
+            }
+        });
+
         for (ori_link, link_range) in markdown_links(&dox) {
             // Bail early for real links.
             if ori_link.contains('/') {
@@ -458,7 +504,7 @@
             };
             let (res, fragment) = {
                 let mut kind = None;
-                let path_str = if let Some(prefix) =
+                let mut path_str = if let Some(prefix) =
                     ["struct@", "enum@", "type@", "trait@", "union@"]
                         .iter()
                         .find(|p| link.starts_with(**p))
@@ -512,6 +558,15 @@
                 let base_node =
                     if item.is_mod() && item.attrs.inner_docs { None } else { parent_node };
 
+                let resolved_self;
+                // replace `Self` with suitable item's parent name
+                if path_str.starts_with("Self::") {
+                    if let Some(ref name) = parent_name {
+                        resolved_self = format!("{}::{}", name, &path_str[6..]);
+                        path_str = &resolved_self;
+                    }
+                }
+
                 match kind {
                     Some(ns @ ValueNS) => {
                         match self.resolve(
@@ -520,7 +575,7 @@
                             &current_item,
                             base_node,
                             &extra_fragment,
-                            None,
+                            Some(&item),
                         ) {
                             Ok(res) => res,
                             Err(ErrorKind::ResolutionFailure) => {
@@ -543,7 +598,7 @@
                             &current_item,
                             base_node,
                             &extra_fragment,
-                            None,
+                            Some(&item),
                         ) {
                             Ok(res) => res,
                             Err(ErrorKind::ResolutionFailure) => {
@@ -568,7 +623,7 @@
                                 &current_item,
                                 base_node,
                                 &extra_fragment,
-                                None,
+                                Some(&item),
                             ) {
                                 Err(ErrorKind::AnchorFailure(msg)) => {
                                     anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 8e743ac..deb9eb5 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -882,7 +882,7 @@
     /// Returns `max` if `self` is greater than `max`, and `min` if `self` is
     /// less than `min`. Otherwise this returns `self`.
     ///
-    /// Not that this function returns NaN if the initial value was NaN as
+    /// Note that this function returns NaN if the initial value was NaN as
     /// well.
     ///
     /// # Panics
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index fe64d27..b79e550 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -884,7 +884,7 @@
     /// Returns `max` if `self` is greater than `max`, and `min` if `self` is
     /// less than `min`. Otherwise this returns `self`.
     ///
-    /// Not that this function returns NaN if the initial value was NaN as
+    /// Note that this function returns NaN if the initial value was NaN as
     /// well.
     ///
     /// # Panics
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
index e2092cf..89dd9fb 100644
--- a/src/libstd/future.rs
+++ b/src/libstd/future.rs
@@ -2,4 +2,16 @@
 
 #[doc(inline)]
 #[stable(feature = "futures_api", since = "1.36.0")]
-pub use core::future::*;
+pub use core::future::Future;
+
+#[doc(inline)]
+#[unstable(feature = "gen_future", issue = "50547")]
+pub use core::future::{from_generator, get_context, ResumeTy};
+
+#[doc(inline)]
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+pub use core::future::{pending, ready, Pending, Ready};
+
+#[doc(inline)]
+#[unstable(feature = "into_future", issue = "67644")]
+pub use core::future::IntoFuture;
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index ac07af5..cc3e613 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -266,12 +266,15 @@
 #![feature(external_doc)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
+#![feature(future_readiness_fns)]
+#![feature(gen_future)]
 #![feature(generator_trait)]
 #![feature(global_asm)]
 #![feature(hash_raw_entry)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
 #![feature(int_error_matching)]
+#![feature(into_future)]
 #![feature(integer_atomics)]
 #![feature(lang_items)]
 #![feature(libc)]
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index edc2803..6e2478b 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -856,16 +856,23 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for Ipv4Addr {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address
-        let mut buf = [0u8; IPV4_BUF_LEN];
-        let mut buf_slice = &mut buf[..];
         let octets = self.octets();
-        // Note: The call to write should never fail, hence the unwrap
-        write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
-        let len = IPV4_BUF_LEN - buf_slice.len();
-        // This unsafe is OK because we know what is being written to the buffer
-        let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
-        fmt.pad(buf)
+        // Fast Path: if there's no alignment stuff, write directly to the buffer
+        if fmt.precision().is_none() && fmt.width().is_none() {
+            write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+        } else {
+            const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address
+            let mut buf = [0u8; IPV4_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+
+            // Note: The call to write should never fail, hence the unwrap
+            write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
+            let len = IPV4_BUF_LEN - buf_slice.len();
+
+            // This unsafe is OK because we know what is being written to the buffer
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            fmt.pad(buf)
+        }
     }
 }
 
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs
index fa8670b..048ce24 100644
--- a/src/libstd/sys/unix/ext/process.rs
+++ b/src/libstd/sys/unix/ext/process.rs
@@ -111,7 +111,7 @@
     ///
     /// Set the first process argument, `argv[0]`, to something other than the
     /// default executable path.
-    #[unstable(feature = "process_set_argv0", issue = "66510")]
+    #[stable(feature = "process_set_argv0", since = "1.45.0")]
     fn arg0<S>(&mut self, arg: S) -> &mut process::Command
     where
         S: AsRef<OsStr>;
diff --git a/src/libstd/sys/vxworks/ext/process.rs b/src/libstd/sys/vxworks/ext/process.rs
index 31e691d..c3710f4 100644
--- a/src/libstd/sys/vxworks/ext/process.rs
+++ b/src/libstd/sys/vxworks/ext/process.rs
@@ -111,7 +111,7 @@
     ///
     /// Set the first process argument, `argv[0]`, to something other than the
     /// default executable path.
-    #[unstable(feature = "process_set_argv0", issue = "66510")]
+    #[stable(feature = "process_set_argv0", since = "1.45.0")]
     fn arg0<S>(&mut self, arg: S) -> &mut process::Command
     where
         S: AsRef<OsStr>;
diff --git a/src/libstd/tests/run-time-detect.rs b/src/libstd/tests/run-time-detect.rs
index 2e6d1bc..8dd1a8a 100644
--- a/src/libstd/tests/run-time-detect.rs
+++ b/src/libstd/tests/run-time-detect.rs
@@ -32,6 +32,7 @@
     println!("rdm: {}", is_aarch64_feature_detected!("rdm"));
     println!("rcpc: {}", is_aarch64_feature_detected!("rcpc"));
     println!("dotprod: {}", is_aarch64_feature_detected!("dotprod"));
+    println!("tme: {}", is_aarch64_feature_detected!("tme"));
 }
 
 #[test]
diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs
index 18d41be..cc025da 100644
--- a/src/libunwind/lib.rs
+++ b/src/libunwind/lib.rs
@@ -27,3 +27,7 @@
 #[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
 #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
 extern "C" {}
+
+#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
+#[link(name = "unwind", kind = "static-nobundle")]
+extern "C" {}
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 6c638c5..02dcfb8 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -445,7 +445,7 @@
     const char *TripleStr, const char *CPU, const char *Feature,
     const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc,
     LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
-    bool PositionIndependentExecutable, bool FunctionSections,
+    bool FunctionSections,
     bool DataSections,
     bool TrapUnreachable,
     bool Singlethread,
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index b988d06..24f3562 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -720,7 +720,6 @@
 
 extern "C" LLVMMetadataRef
 LLVMRustDIBuilderCreateSubroutineType(LLVMRustDIBuilderRef Builder,
-                                      LLVMMetadataRef File,
                                       LLVMMetadataRef ParameterTypes) {
   return wrap(Builder->createSubroutineType(
       DITypeRefArray(unwrap<MDTuple>(ParameterTypes))));
@@ -755,7 +754,7 @@
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType(
     LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen,
-    uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding) {
+    uint64_t SizeInBits, unsigned Encoding) {
   return wrap(Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding));
 }
 
@@ -964,9 +963,7 @@
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
     LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
-    const char *Name, size_t NameLen,
-    LLVMMetadataRef Ty, LLVMMetadataRef File, unsigned LineNo,
-    unsigned ColumnNo) {
+    const char *Name, size_t NameLen, LLVMMetadataRef Ty) {
   return wrap(Builder->createTemplateTypeParameter(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty)));
 }
diff --git a/src/test/incremental/issue-72386.rs b/src/test/incremental/issue-72386.rs
new file mode 100644
index 0000000..3dc7f50
--- /dev/null
+++ b/src/test/incremental/issue-72386.rs
@@ -0,0 +1,22 @@
+// revisions: rpass1 cfail1 rpass3
+// only-x86_64
+// Regression test for issue #72386
+// Checks that we don't ICE when switching to an invalid register
+// and back again
+
+#![feature(asm)]
+
+#[cfg(any(rpass1, rpass3))]
+fn main() {
+    unsafe {
+        asm!("nop")
+    }
+}
+
+#[cfg(cfail1)]
+fn main() {
+    unsafe {
+        asm!("nop",out("invalid_reg")_)
+        //[cfail1]~^ ERROR invalid register
+    }
+}
diff --git "a/src/test/mir-opt/generator-drop-cleanup/rustc.main-\173\173closure\175\175.generator_drop.0.mir" "b/src/test/mir-opt/generator-drop-cleanup/rustc.main-\173\173closure\175\175.generator_drop.0.mir"
index 382273a..6a32a42 100644
--- "a/src/test/mir-opt/generator-drop-cleanup/rustc.main-\173\173closure\175\175.generator_drop.0.mir"
+++ "b/src/test/mir-opt/generator-drop-cleanup/rustc.main-\173\173closure\175\175.generator_drop.0.mir"
@@ -9,7 +9,7 @@
     let mut _5: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14
     let mut _7: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:10:18: 10:18
     let mut _8: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
-    let mut _9: isize;                   // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+    let mut _9: u32;                     // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     scope 1 {
         debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator-drop-cleanup.rs:11:13: 11:15
     }
diff --git "a/src/test/mir-opt/generator-tiny/rustc.main-\173\173closure\175\175.generator_resume.0.mir" "b/src/test/mir-opt/generator-tiny/rustc.main-\173\173closure\175\175.generator_resume.0.mir"
index 75c2fb3..c73dea5 100644
--- "a/src/test/mir-opt/generator-tiny/rustc.main-\173\173closure\175\175.generator_resume.0.mir"
+++ "b/src/test/mir-opt/generator-tiny/rustc.main-\173\173closure\175\175.generator_resume.0.mir"
@@ -12,7 +12,7 @@
     let _8: ();                          // in scope 0 at $DIR/generator-tiny.rs:23:13: 23:21
     let mut _9: ();                      // in scope 0 at $DIR/generator-tiny.rs:19:25: 19:25
     let _10: u8;                         // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19
-    let mut _11: isize;                  // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+    let mut _11: u32;                    // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
     scope 1 {
         debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15
     }
diff --git a/src/test/rustdoc/intra-link-self.rs b/src/test/rustdoc/intra-link-self.rs
index acf975f..97752d5 100644
--- a/src/test/rustdoc/intra-link-self.rs
+++ b/src/test/rustdoc/intra-link-self.rs
@@ -1,5 +1,7 @@
 #![crate_name = "foo"]
 
+// ignore-tidy-linelength
+
 // @has foo/index.html '//a/@href' '../foo/struct.Foo.html#method.new'
 // @has foo/struct.Foo.html '//a/@href' '../foo/struct.Foo.html#method.new'
 
@@ -27,3 +29,89 @@
         unimplemented!()
     }
 }
+
+pub struct MyStruct {
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#structfield.struct_field'
+
+    /// [`struct_field`]
+    ///
+    /// [`struct_field`]: Self::struct_field
+    pub struct_field: u8,
+}
+
+pub enum MyEnum {
+    // @has foo/enum.MyEnum.html '//a/@href' '../foo/enum.MyEnum.html#EnumVariant.v'
+
+    /// [`EnumVariant`]
+    ///
+    /// [`EnumVariant`]: Self::EnumVariant
+    EnumVariant,
+}
+
+pub union MyUnion {
+    // @has foo/union.MyUnion.html '//a/@href' '../foo/union.MyUnion.html#structfield.union_field'
+
+    /// [`union_field`]
+    ///
+    /// [`union_field`]: Self::union_field
+    pub union_field: f32,
+}
+
+pub trait MyTrait {
+    // @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedtype.AssoType'
+
+    /// [`AssoType`]
+    ///
+    /// [`AssoType`]: Self::AssoType
+    type AssoType;
+
+    // @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedconstant.ASSO_CONST'
+
+    /// [`ASSO_CONST`]
+    ///
+    /// [`ASSO_CONST`]: Self::ASSO_CONST
+    const ASSO_CONST: i32 = 1;
+
+    // @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#method.asso_fn'
+
+    /// [`asso_fn`]
+    ///
+    /// [`asso_fn`]: Self::asso_fn
+    fn asso_fn() {}
+}
+
+impl MyStruct {
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.for_impl'
+
+    /// [`for_impl`]
+    ///
+    /// [`for_impl`]: Self::for_impl
+    pub fn for_impl() {
+        unimplemented!()
+    }
+}
+
+impl MyTrait for MyStruct {
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedtype.AssoType'
+
+    /// [`AssoType`]
+    ///
+    /// [`AssoType`]: Self::AssoType
+    type AssoType = u32;
+
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedconstant.ASSO_CONST'
+
+    /// [`ASSO_CONST`]
+    ///
+    /// [`ASSO_CONST`]: Self::ASSO_CONST
+    const ASSO_CONST: i32 = 10;
+
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.asso_fn'
+
+    /// [`asso_fn`]
+    ///
+    /// [`asso_fn`]: Self::asso_fn
+    fn asso_fn() {
+        unimplemented!()
+    }
+}
diff --git a/src/test/rustdoc/issue-72340.rs b/src/test/rustdoc/issue-72340.rs
new file mode 100644
index 0000000..6ed3bfb
--- /dev/null
+++ b/src/test/rustdoc/issue-72340.rs
@@ -0,0 +1,19 @@
+#![crate_name = "foo"]
+
+pub struct Body;
+
+impl Body {
+    pub fn empty() -> Self {
+        Body
+    }
+
+}
+
+impl Default for Body {
+    // @has foo/struct.Body.html '//a/@href' '../foo/struct.Body.html#method.empty'
+
+    /// Returns [`Body::empty()`](Body::empty).
+    fn default() -> Body {
+        Body::empty()
+    }
+}
diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs
index 636fafc..000acf1 100644
--- a/src/test/ui/async-await/async-fn-size-moved-locals.rs
+++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs
@@ -114,5 +114,5 @@
     assert_eq!(1026, std::mem::size_of_val(&single_with_noop()));
     assert_eq!(3078, std::mem::size_of_val(&joined()));
     assert_eq!(3079, std::mem::size_of_val(&joined_with_noop()));
-    assert_eq!(7181, std::mem::size_of_val(&mixed_sizes()));
+    assert_eq!(6157, std::mem::size_of_val(&mixed_sizes()));
 }
diff --git a/src/test/ui/borrowck/issue-45983.migrate.stderr b/src/test/ui/borrowck/issue-45983.migrate.stderr
deleted file mode 100644
index c1564cf..0000000
--- a/src/test/ui/borrowck/issue-45983.migrate.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error: borrowed data cannot be stored outside of its closure
-  --> $DIR/issue-45983.rs:20:27
-   |
-LL |     let x = None;
-   |         - borrowed data cannot be stored into here...
-LL |     give_any(|y| x = Some(y));
-   |              ---          ^ cannot be stored outside of its closure
-   |              |
-   |              ...because it cannot outlive this closure
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr
deleted file mode 100644
index 51bb4de..0000000
--- a/src/test/ui/borrowck/issue-45983.nll.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0521]: borrowed data escapes outside of closure
-  --> $DIR/issue-45983.rs:20:18
-   |
-LL |     let x = None;
-   |         - `x` declared here, outside of the closure body
-LL |     give_any(|y| x = Some(y));
-   |               -  ^^^^^^^^^^^ `y` escapes the closure body here
-   |               |
-   |               `y` is a reference that is only valid in the closure body
-
-error[E0594]: cannot assign to `x`, as it is not declared as mutable
-  --> $DIR/issue-45983.rs:20:18
-   |
-LL |     let x = None;
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     give_any(|y| x = Some(y));
-   |                  ^^^^^^^^^^^ cannot assign
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/issue-45983.rs b/src/test/ui/borrowck/issue-45983.rs
index 3cd2820..6784f6f 100644
--- a/src/test/ui/borrowck/issue-45983.rs
+++ b/src/test/ui/borrowck/issue-45983.rs
@@ -1,24 +1,12 @@
 // As documented in Issue #45983, this test is evaluating the quality
 // of our diagnostics on erroneous code using higher-ranked closures.
 
-// revisions: migrate nll
-
-// Since we are testing nll (and migration) explicitly as a separate
-// revisions, don't worry about the --compare-mode=nll on this test.
-
-// ignore-compare-mode-nll
-// ignore-compare-mode-polonius
-
-//[nll]compile-flags: -Z borrowck=mir
-
 fn give_any<F: for<'r> FnOnce(&'r ())>(f: F) {
     f(&());
 }
 
 fn main() {
-    let x = None;
+    let mut x = None;
     give_any(|y| x = Some(y));
-    //[migrate]~^ ERROR borrowed data cannot be stored outside of its closure
-    //[nll]~^^ ERROR borrowed data escapes outside of closure
-    //[nll]~| ERROR cannot assign to `x`, as it is not declared as mutable
+    //~^ ERROR borrowed data escapes outside of closure
 }
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/issue-45983.stderr
similarity index 81%
rename from src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
rename to src/test/ui/borrowck/issue-45983.stderr
index 68a0fe0..efd414a 100644
--- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
+++ b/src/test/ui/borrowck/issue-45983.stderr
@@ -1,9 +1,9 @@
 error[E0521]: borrowed data escapes outside of closure
-  --> $DIR/regions-escape-bound-fn-2.rs:8:18
+  --> $DIR/issue-45983.rs:10:18
    |
 LL |     let mut x = None;
    |         ----- `x` declared here, outside of the closure body
-LL |     with_int(|y| x = Some(y));
+LL |     give_any(|y| x = Some(y));
    |               -  ^^^^^^^^^^^ `y` escapes the closure body here
    |               |
    |               `y` is a reference that is only valid in the closure body
diff --git a/src/test/ui/borrowck/issue-7573.nll.stderr b/src/test/ui/borrowck/issue-7573.nll.stderr
deleted file mode 100644
index 20afecf..0000000
--- a/src/test/ui/borrowck/issue-7573.nll.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0521]: borrowed data escapes outside of closure
-  --> $DIR/issue-7573.rs:21:9
-   |
-LL |     let mut lines_to_use: Vec<&CrateId> = Vec::new();
-   |         ---------------- `lines_to_use` declared here, outside of the closure body
-LL |
-LL |     let push_id = |installed_id: &CrateId| {
-   |                    ------------ `installed_id` is a reference that is only valid in the closure body
-...
-LL |         lines_to_use.push(installed_id);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/borrowck/issue-7573.rs b/src/test/ui/borrowck/issue-7573.rs
index 20a6a5c..7c07411 100644
--- a/src/test/ui/borrowck/issue-7573.rs
+++ b/src/test/ui/borrowck/issue-7573.rs
@@ -1,36 +1,34 @@
 pub struct CrateId {
     local_path: String,
-    junk: String
+    junk: String,
 }
 
 impl CrateId {
     fn new(s: &str) -> CrateId {
-        CrateId {
-            local_path: s.to_string(),
-            junk: "wutevs".to_string()
-        }
+        CrateId { local_path: s.to_string(), junk: "wutevs".to_string() }
     }
 }
 
 pub fn remove_package_from_database() {
     let mut lines_to_use: Vec<&CrateId> = Vec::new();
-        //~^ NOTE cannot infer an appropriate lifetime
+    //~^ NOTE `lines_to_use` declared here, outside of the closure body
     let push_id = |installed_id: &CrateId| {
-        //~^ NOTE borrowed data cannot outlive this closure
-        //~| NOTE ...so that variable is valid at time of its declaration
+        //~^ NOTE `installed_id` is a reference that is only valid in the closure body
         lines_to_use.push(installed_id);
-        //~^ ERROR borrowed data cannot be stored outside of its closure
-        //~| NOTE cannot be stored outside of its closure
+        //~^ ERROR borrowed data escapes outside of closure
+        //~| NOTE `installed_id` escapes the closure body here
     };
     list_database(push_id);
 
     for l in &lines_to_use {
         println!("{}", l.local_path);
     }
-
 }
 
-pub fn list_database<F>(mut f: F) where F: FnMut(&CrateId) {
+pub fn list_database<F>(mut f: F)
+where
+    F: FnMut(&CrateId),
+{
     let stuff = ["foo", "bar"];
 
     for l in &stuff {
diff --git a/src/test/ui/borrowck/issue-7573.stderr b/src/test/ui/borrowck/issue-7573.stderr
index 32b3ef7..815419d 100644
--- a/src/test/ui/borrowck/issue-7573.stderr
+++ b/src/test/ui/borrowck/issue-7573.stderr
@@ -1,16 +1,14 @@
-error: borrowed data cannot be stored outside of its closure
-  --> $DIR/issue-7573.rs:21:27
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/issue-7573.rs:17:9
    |
 LL |     let mut lines_to_use: Vec<&CrateId> = Vec::new();
-   |                               - cannot infer an appropriate lifetime...
+   |         ---------------- `lines_to_use` declared here, outside of the closure body
 LL |
 LL |     let push_id = |installed_id: &CrateId| {
-   |         -------   ------------------------ borrowed data cannot outlive this closure
-   |         |
-   |         ...so that variable is valid at time of its declaration
-...
+   |                    ------------ `installed_id` is a reference that is only valid in the closure body
+LL |
 LL |         lines_to_use.push(installed_id);
-   |                           ^^^^^^^^^^^^ cannot be stored outside of its closure
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.rs b/src/test/ui/borrowck/regions-escape-bound-fn-2.rs
index cb42303..0e98d98 100644
--- a/src/test/ui/borrowck/regions-escape-bound-fn-2.rs
+++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.rs
@@ -1,4 +1,7 @@
-fn with_int<F>(f: F) where F: FnOnce(&isize) {
+fn with_int<F>(f: F)
+where
+    F: FnOnce(&isize),
+{
     let x = 3;
     f(&x);
 }
@@ -6,5 +9,5 @@
 fn main() {
     let mut x = None;
     with_int(|y| x = Some(y));
-    //~^ ERROR borrowed data cannot be stored outside of its closure
+    //~^ ERROR borrowed data escapes outside of closure
 }
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr
index 4b37eda..1dc60bb 100644
--- a/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr
+++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr
@@ -1,12 +1,12 @@
-error: borrowed data cannot be stored outside of its closure
-  --> $DIR/regions-escape-bound-fn-2.rs:8:27
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-escape-bound-fn-2.rs:11:18
    |
 LL |     let mut x = None;
-   |         ----- borrowed data cannot be stored into here...
+   |         ----- `x` declared here, outside of the closure body
 LL |     with_int(|y| x = Some(y));
-   |              ---          ^ cannot be stored outside of its closure
-   |              |
-   |              ...because it cannot outlive this closure
+   |               -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |               |
+   |               `y` is a reference that is only valid in the closure body
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr
deleted file mode 100644
index d304de9..0000000
--- a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0521]: borrowed data escapes outside of closure
-  --> $DIR/regions-escape-bound-fn.rs:8:18
-   |
-LL |     let mut x: Option<&isize> = None;
-   |         ----- `x` declared here, outside of the closure body
-LL |     with_int(|y| x = Some(y));
-   |               -  ^^^^^^^^^^^ `y` escapes the closure body here
-   |               |
-   |               `y` is a reference that is only valid in the closure body
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.rs b/src/test/ui/borrowck/regions-escape-bound-fn.rs
index 772df3e..f896ae7 100644
--- a/src/test/ui/borrowck/regions-escape-bound-fn.rs
+++ b/src/test/ui/borrowck/regions-escape-bound-fn.rs
@@ -1,4 +1,7 @@
-fn with_int<F>(f: F) where F: FnOnce(&isize) {
+fn with_int<F>(f: F)
+where
+    F: FnOnce(&isize),
+{
     let x = 3;
     f(&x);
 }
@@ -6,5 +9,5 @@
 fn main() {
     let mut x: Option<&isize> = None;
     with_int(|y| x = Some(y));
-    //~^ ERROR borrowed data cannot be stored outside of its closure
+    //~^ ERROR borrowed data escapes outside of closure
 }
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.stderr
index 4973d53..5c548ec 100644
--- a/src/test/ui/borrowck/regions-escape-bound-fn.stderr
+++ b/src/test/ui/borrowck/regions-escape-bound-fn.stderr
@@ -1,12 +1,12 @@
-error: borrowed data cannot be stored outside of its closure
-  --> $DIR/regions-escape-bound-fn.rs:8:27
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-escape-bound-fn.rs:11:18
    |
 LL |     let mut x: Option<&isize> = None;
-   |         ----- borrowed data cannot be stored into here...
+   |         ----- `x` declared here, outside of the closure body
 LL |     with_int(|y| x = Some(y));
-   |              ---          ^ cannot be stored outside of its closure
-   |              |
-   |              ...because it cannot outlive this closure
+   |               -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |               |
+   |               `y` is a reference that is only valid in the closure body
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr
deleted file mode 100644
index d993130..0000000
--- a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0521]: borrowed data escapes outside of closure
-  --> $DIR/regions-escape-unboxed-closure.rs:6:23
-   |
-LL |     let mut x: Option<&isize> = None;
-   |         ----- `x` declared here, outside of the closure body
-LL |     with_int(&mut |y| x = Some(y));
-   |                    -  ^^^^^^^^^^^ `y` escapes the closure body here
-   |                    |
-   |                    `y` is a reference that is only valid in the closure body
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.rs b/src/test/ui/borrowck/regions-escape-unboxed-closure.rs
index d8bef92..f01e471 100644
--- a/src/test/ui/borrowck/regions-escape-unboxed-closure.rs
+++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.rs
@@ -1,8 +1,7 @@
-fn with_int(f: &mut dyn FnMut(&isize)) {
-}
+fn with_int(f: &mut dyn FnMut(&isize)) {}
 
 fn main() {
     let mut x: Option<&isize> = None;
     with_int(&mut |y| x = Some(y));
-    //~^ ERROR borrowed data cannot be stored outside of its closure
+    //~^ ERROR borrowed data escapes outside of closure
 }
diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr
index 047e290..f2a49e7 100644
--- a/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr
+++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr
@@ -1,12 +1,12 @@
-error: borrowed data cannot be stored outside of its closure
-  --> $DIR/regions-escape-unboxed-closure.rs:6:32
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-escape-unboxed-closure.rs:5:23
    |
 LL |     let mut x: Option<&isize> = None;
-   |         ----- borrowed data cannot be stored into here...
+   |         ----- `x` declared here, outside of the closure body
 LL |     with_int(&mut |y| x = Some(y));
-   |                   ---          ^ cannot be stored outside of its closure
-   |                   |
-   |                   ...because it cannot outlive this closure
+   |                    -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |                    |
+   |                    `y` is a reference that is only valid in the closure body
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
deleted file mode 100644
index 89107e7..0000000
--- a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
+++ /dev/null
@@ -1,123 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:8:5
-   |
-LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
-   |                                     --            -- has type `core::ffi::VaListImpl<'1>`
-   |                                     |
-   |                                     lifetime `'f` defined here
-LL |     ap
-   |     ^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'f`
-
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:8:5
-   |
-LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
-   |                                     --            -- has type `core::ffi::VaListImpl<'1>`
-   |                                     |
-   |                                     lifetime `'f` defined here
-LL |     ap
-   |     ^^ returning this value requires that `'1` must outlive `'f`
-
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:12:5
-   |
-LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> {
-   |                                               -- has type `core::ffi::VaListImpl<'1>`
-LL |     ap
-   |     ^^ returning this value requires that `'1` must outlive `'static`
-
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:16:33
-   |
-LL |     let _ = ap.with_copy(|ap| { ap });
-   |                           ---   ^^ returning this value requires that `'1` must outlive `'2`
-   |                           | |
-   |                           | return type of closure is core::ffi::VaList<'2, '_>
-   |                           has type `core::ffi::VaList<'1, '_>`
-
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:20:5
-   |
-LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
-   |                                               |
-   |                                               has type `&mut core::ffi::VaListImpl<'1>`
-LL |     *ap0 = ap1;
-   |     ^^^^ assignment requires that `'1` must outlive `'2`
-
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:20:5
-   |
-LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
-   |                                               |
-   |                                               has type `&mut core::ffi::VaListImpl<'1>`
-LL |     *ap0 = ap1;
-   |     ^^^^ assignment requires that `'2` must outlive `'1`
-
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:24:5
-   |
-LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               ---                   ------- has type `core::ffi::VaListImpl<'2>`
-   |                                               |
-   |                                               has type `&mut core::ffi::VaListImpl<'1>`
-LL |     ap0 = &mut ap1;
-   |     ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
-
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:24:5
-   |
-LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               ---                   ------- has type `core::ffi::VaListImpl<'2>`
-   |                                               |
-   |                                               has type `&mut core::ffi::VaListImpl<'1>`
-LL |     ap0 = &mut ap1;
-   |     ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
-
-error[E0384]: cannot assign to immutable argument `ap0`
-  --> $DIR/variadic-ffi-4.rs:24:5
-   |
-LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               --- help: make this binding mutable: `mut ap0`
-LL |     ap0 = &mut ap1;
-   |     ^^^^^^^^^^^^^^ cannot assign to immutable argument
-
-error[E0597]: `ap1` does not live long enough
-  --> $DIR/variadic-ffi-4.rs:24:11
-   |
-LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                                    - let's call the lifetime of this reference `'3`
-LL |     ap0 = &mut ap1;
-   |     ------^^^^^^^^
-   |     |     |
-   |     |     borrowed value does not live long enough
-   |     assignment requires that `ap1` is borrowed for `'3`
-...
-LL | }
-   | - `ap1` dropped here while still borrowed
-
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:31:12
-   |
-LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
-   |                                               |
-   |                                               has type `&mut core::ffi::VaListImpl<'1>`
-LL |     *ap0 = ap1.clone();
-   |            ^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
-
-error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-4.rs:31:12
-   |
-LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
-   |                                               |
-   |                                               has type `&mut core::ffi::VaListImpl<'1>`
-LL |     *ap0 = ap1.clone();
-   |            ^^^^^^^^^^^ argument requires that `'2` must outlive `'1`
-
-error: aborting due to 12 previous errors
-
-Some errors have detailed explanations: E0384, E0597.
-For more information about an error, try `rustc --explain E0384`.
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.rs b/src/test/ui/c-variadic/variadic-ffi-4.rs
index a4d658c..8064037 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.rs
+++ b/src/test/ui/c-variadic/variadic-ffi-4.rs
@@ -1,32 +1,38 @@
-#![crate_type="lib"]
+#![crate_type = "lib"]
 #![no_std]
 #![feature(c_variadic)]
 
 use core::ffi::{VaList, VaListImpl};
 
 pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
-    ap //~ ERROR: mismatched types
+    ap
+    //~^ ERROR: lifetime may not live long enough
+    //~| ERROR: lifetime may not live long enough
 }
 
 pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> {
-    ap //~ ERROR: mismatched types
+    ap //~ ERROR: lifetime may not live long enough
 }
 
 pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) {
-    let _ = ap.with_copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime
+    let _ = ap.with_copy(|ap| ap); //~ ERROR: lifetime may not live long enough
 }
 
 pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-    *ap0 = ap1; //~ ERROR: mismatched types
+    *ap0 = ap1;
+    //~^ ERROR: lifetime may not live long enough
+    //~| ERROR: lifetime may not live long enough
 }
 
-pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
+pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
     ap0 = &mut ap1;
-    //~^ ERROR: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long
-    //~| ERROR: mismatched types
-    //~| ERROR: cannot infer an appropriate lifetime
+    //~^ ERROR: `ap1` does not live long enough
+    //~| ERROR: lifetime may not live long enough
+    //~| ERROR: lifetime may not live long enough
 }
 
 pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-    *ap0 = ap1.clone(); //~ ERROR: mismatched types
+    *ap0 = ap1.clone();
+    //~^ ERROR: lifetime may not live long enough
+    //~| ERROR: lifetime may not live long enough
 }
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr
index cd4cd8b..6562350 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr
@@ -1,217 +1,114 @@
-error[E0308]: mismatched types
+error: lifetime may not live long enough
   --> $DIR/variadic-ffi-4.rs:8:5
    |
+LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
+   |                                     --            -- has type `core::ffi::VaListImpl<'1>`
+   |                                     |
+   |                                     lifetime `'f` defined here
 LL |     ap
-   |     ^^ lifetime mismatch
-   |
-   = note: expected struct `core::ffi::VaListImpl<'f>`
-              found struct `core::ffi::VaListImpl<'_>`
-note: the scope of call-site for function at 7:78...
-  --> $DIR/variadic-ffi-4.rs:7:78
-   |
-LL |   pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
-   |  ______________________________________________________________________________^
-LL | |     ap
-LL | | }
-   | |_^
-note: ...does not necessarily outlive the lifetime `'f` as defined on the function body at 7:37
-  --> $DIR/variadic-ffi-4.rs:7:37
+   |     ^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'f`
+
+error: lifetime may not live long enough
+  --> $DIR/variadic-ffi-4.rs:8:5
    |
 LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
-   |                                     ^^
-
-error[E0308]: mismatched types
-  --> $DIR/variadic-ffi-4.rs:12:5
-   |
+   |                                     --            -- has type `core::ffi::VaListImpl<'1>`
+   |                                     |
+   |                                     lifetime `'f` defined here
 LL |     ap
-   |     ^^ lifetime mismatch
-   |
-   = note: expected struct `core::ffi::VaListImpl<'static>`
-              found struct `core::ffi::VaListImpl<'_>`
-note: the scope of call-site for function at 11:79...
-  --> $DIR/variadic-ffi-4.rs:11:79
-   |
-LL |   pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> {
-   |  _______________________________________________________________________________^
-LL | |     ap
-LL | | }
-   | |_^
-   = note: ...does not necessarily outlive the static lifetime
+   |     ^^ returning this value requires that `'1` must outlive `'f`
 
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/variadic-ffi-4.rs:16:33
+error: lifetime may not live long enough
+  --> $DIR/variadic-ffi-4.rs:14:5
    |
-LL |     let _ = ap.with_copy(|ap| { ap });
-   |                                 ^^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 16:26...
-  --> $DIR/variadic-ffi-4.rs:16:26
-   |
-LL |     let _ = ap.with_copy(|ap| { ap });
-   |                          ^^^^^^^^^^^
-note: ...so that the expression is assignable
-  --> $DIR/variadic-ffi-4.rs:16:33
-   |
-LL |     let _ = ap.with_copy(|ap| { ap });
-   |                                 ^^
-   = note: expected  `core::ffi::VaList<'_, '_>`
-              found  `core::ffi::VaList<'_, '_>`
-note: but, the lifetime must be valid for the method call at 16:13...
-  --> $DIR/variadic-ffi-4.rs:16:13
-   |
-LL |     let _ = ap.with_copy(|ap| { ap });
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...so type `core::ffi::VaList<'_, '_>` of expression is valid during the expression
-  --> $DIR/variadic-ffi-4.rs:16:13
-   |
-LL |     let _ = ap.with_copy(|ap| { ap });
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> {
+   |                                               -- has type `core::ffi::VaListImpl<'1>`
+LL |     ap
+   |     ^^ returning this value requires that `'1` must outlive `'static`
 
-error[E0308]: mismatched types
-  --> $DIR/variadic-ffi-4.rs:20:12
+error: lifetime may not live long enough
+  --> $DIR/variadic-ffi-4.rs:18:31
    |
+LL |     let _ = ap.with_copy(|ap| ap);
+   |                           --- ^^ returning this value requires that `'1` must outlive `'2`
+   |                           | |
+   |                           | return type of closure is core::ffi::VaList<'2, '_>
+   |                           has type `core::ffi::VaList<'1, '_>`
+
+error: lifetime may not live long enough
+  --> $DIR/variadic-ffi-4.rs:22:5
+   |
+LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
+   |                                               |
+   |                                               has type `&mut core::ffi::VaListImpl<'1>`
 LL |     *ap0 = ap1;
-   |            ^^^ lifetime mismatch
-   |
-   = note: expected struct `core::ffi::VaListImpl<'_>`
-              found struct `core::ffi::VaListImpl<'_>`
-note: the scope of call-site for function at 19:87...
-  --> $DIR/variadic-ffi-4.rs:19:87
-   |
-LL |   pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-   |  _______________________________________________________________________________________^
-LL | |     *ap0 = ap1;
-LL | | }
-   | |_^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 19:1
-  --> $DIR/variadic-ffi-4.rs:19:1
-   |
-LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     *ap0 = ap1;
-LL | | }
-   | |_^
+   |     ^^^^ assignment requires that `'1` must outlive `'2`
 
-error[E0490]: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long
-  --> $DIR/variadic-ffi-4.rs:24:11
+error: lifetime may not live long enough
+  --> $DIR/variadic-ffi-4.rs:22:5
    |
-LL |     ap0 = &mut ap1;
-   |           ^^^^^^^^
-   |
-note: the type is valid for the anonymous lifetime #1 defined on the function body at 23:1
-  --> $DIR/variadic-ffi-4.rs:23:1
-   |
-LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     ap0 = &mut ap1;
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_^
-note: but the borrow lasts for the scope of call-site for function at 23:83
-  --> $DIR/variadic-ffi-4.rs:23:83
-   |
-LL |   pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-   |  ___________________________________________________________________________________^
-LL | |     ap0 = &mut ap1;
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_^
+LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
+   |                                               |
+   |                                               has type `&mut core::ffi::VaListImpl<'1>`
+LL |     *ap0 = ap1;
+   |     ^^^^ assignment requires that `'2` must outlive `'1`
 
-error[E0308]: mismatched types
-  --> $DIR/variadic-ffi-4.rs:24:11
+error: lifetime may not live long enough
+  --> $DIR/variadic-ffi-4.rs:28:5
    |
+LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
+   |                                               |
+   |                                               has type `&mut core::ffi::VaListImpl<'1>`
 LL |     ap0 = &mut ap1;
-   |           ^^^^^^^^ lifetime mismatch
-   |
-   = note: expected mutable reference `&mut core::ffi::VaListImpl<'_>`
-              found mutable reference `&mut core::ffi::VaListImpl<'_>`
-note: the scope of call-site for function at 23:83...
-  --> $DIR/variadic-ffi-4.rs:23:83
-   |
-LL |   pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-   |  ___________________________________________________________________________________^
-LL | |     ap0 = &mut ap1;
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 23:1
-  --> $DIR/variadic-ffi-4.rs:23:1
-   |
-LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     ap0 = &mut ap1;
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_^
+   |     ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
 
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
-  --> $DIR/variadic-ffi-4.rs:24:11
+error: lifetime may not live long enough
+  --> $DIR/variadic-ffi-4.rs:28:5
    |
+LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
+   |                                               |
+   |                                               has type `&mut core::ffi::VaListImpl<'1>`
 LL |     ap0 = &mut ap1;
-   |           ^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the scope of call-site for function at 23:83...
-  --> $DIR/variadic-ffi-4.rs:23:83
-   |
-LL |   pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-   |  ___________________________________________________________________________________^
-LL | |     ap0 = &mut ap1;
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_^
-note: ...so that the type `core::ffi::VaListImpl<'_>` is not borrowed for too long
-  --> $DIR/variadic-ffi-4.rs:24:11
-   |
-LL |     ap0 = &mut ap1;
-   |           ^^^^^^^^
-note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 23:1...
-  --> $DIR/variadic-ffi-4.rs:23:1
-   |
-LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     ap0 = &mut ap1;
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/variadic-ffi-4.rs:24:11
-   |
-LL |     ap0 = &mut ap1;
-   |           ^^^^^^^^
+   |     ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
 
-error[E0308]: mismatched types
-  --> $DIR/variadic-ffi-4.rs:31:12
+error[E0597]: `ap1` does not live long enough
+  --> $DIR/variadic-ffi-4.rs:28:11
    |
+LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+   |                                                        - let's call the lifetime of this reference `'3`
+LL |     ap0 = &mut ap1;
+   |     ------^^^^^^^^
+   |     |     |
+   |     |     borrowed value does not live long enough
+   |     assignment requires that `ap1` is borrowed for `'3`
+...
+LL | }
+   | - `ap1` dropped here while still borrowed
+
+error: lifetime may not live long enough
+  --> $DIR/variadic-ffi-4.rs:35:12
+   |
+LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
+   |                                               |
+   |                                               has type `&mut core::ffi::VaListImpl<'1>`
 LL |     *ap0 = ap1.clone();
-   |            ^^^^^^^^^^^ lifetime mismatch
-   |
-   = note: expected struct `core::ffi::VaListImpl<'_>`
-              found struct `core::ffi::VaListImpl<'_>`
-note: the scope of call-site for function at 30:87...
-  --> $DIR/variadic-ffi-4.rs:30:87
-   |
-LL |   pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-   |  _______________________________________________________________________________________^
-LL | |     *ap0 = ap1.clone();
-LL | | }
-   | |_^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 30:1
-  --> $DIR/variadic-ffi-4.rs:30:1
-   |
-LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-LL | |     *ap0 = ap1.clone();
-LL | | }
-   | |_^
+   |            ^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
 
-error: aborting due to 8 previous errors
+error: lifetime may not live long enough
+  --> $DIR/variadic-ffi-4.rs:35:12
+   |
+LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
+   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
+   |                                               |
+   |                                               has type `&mut core::ffi::VaListImpl<'1>`
+LL |     *ap0 = ap1.clone();
+   |            ^^^^^^^^^^^ argument requires that `'2` must outlive `'1`
 
-Some errors have detailed explanations: E0308, E0495.
-For more information about an error, try `rustc --explain E0308`.
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr
new file mode 100644
index 0000000..52bca8d
--- /dev/null
+++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/expect-region-supply-region-2.rs:14:30
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              -- lifetime `'x` defined here
+...
+LL |     closure_expecting_bound(|x: &'x u32| {
+   |                              ^  - let's call the lifetime of this reference `'1`
+   |                              |
+   |                              requires that `'1` must outlive `'x`
+
+error: lifetime may not live long enough
+  --> $DIR/expect-region-supply-region-2.rs:14:30
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              -- lifetime `'x` defined here
+...
+LL |     closure_expecting_bound(|x: &'x u32| {
+   |                              ^ requires that `'x` must outlive `'static`
+   |
+   = help: consider replacing `'x` with `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.rs b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.rs
new file mode 100644
index 0000000..7405b1a
--- /dev/null
+++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.rs
@@ -0,0 +1,24 @@
+#![allow(warnings)]
+
+fn closure_expecting_bound<F>(_: F)
+where
+    F: FnOnce(&u32),
+{
+}
+
+fn expect_bound_supply_named<'x>() {
+    let mut f: Option<&u32> = None;
+
+    // Here we give a type annotation that `x` should be free. We get
+    // an error because of that.
+    closure_expecting_bound(|x: &'x u32| {
+        //~^ ERROR mismatched types
+        //~| ERROR mismatched types
+
+        // Borrowck doesn't get a chance to run, but if it did it should error
+        // here.
+        f = Some(x);
+    });
+}
+
+fn main() {}
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr
new file mode 100644
index 0000000..7f52790
--- /dev/null
+++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr
@@ -0,0 +1,55 @@
+error[E0308]: mismatched types
+  --> $DIR/expect-region-supply-region-2.rs:14:33
+   |
+LL |     closure_expecting_bound(|x: &'x u32| {
+   |                                 ^^^^^^^ lifetime mismatch
+   |
+   = note: expected reference `&u32`
+              found reference `&'x u32`
+note: the anonymous lifetime #2 defined on the body at 14:29...
+  --> $DIR/expect-region-supply-region-2.rs:14:29
+   |
+LL |       closure_expecting_bound(|x: &'x u32| {
+   |  _____________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |         f = Some(x);
+LL | |     });
+   | |_____^
+note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 9:30
+  --> $DIR/expect-region-supply-region-2.rs:9:30
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              ^^
+
+error[E0308]: mismatched types
+  --> $DIR/expect-region-supply-region-2.rs:14:33
+   |
+LL |     closure_expecting_bound(|x: &'x u32| {
+   |                                 ^^^^^^^ lifetime mismatch
+   |
+   = note: expected reference `&u32`
+              found reference `&'x u32`
+note: the lifetime `'x` as defined on the function body at 9:30...
+  --> $DIR/expect-region-supply-region-2.rs:9:30
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              ^^
+note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 14:29
+  --> $DIR/expect-region-supply-region-2.rs:14:29
+   |
+LL |       closure_expecting_bound(|x: &'x u32| {
+   |  _____________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |         f = Some(x);
+LL | |     });
+   | |_____^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr
deleted file mode 100644
index d7d716e..0000000
--- a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr
+++ /dev/null
@@ -1,44 +0,0 @@
-error[E0521]: borrowed data escapes outside of closure
-  --> $DIR/expect-region-supply-region.rs:18:9
-   |
-LL |     let mut f: Option<&u32> = None;
-   |         ----- `f` declared here, outside of the closure body
-LL |     closure_expecting_bound(|x| {
-   |                              - `x` is a reference that is only valid in the closure body
-LL |         f = Some(x);
-   |         ^^^^^^^^^^^ `x` escapes the closure body here
-
-error[E0521]: borrowed data escapes outside of closure
-  --> $DIR/expect-region-supply-region.rs:28:9
-   |
-LL |     let mut f: Option<&u32> = None;
-   |         ----- `f` declared here, outside of the closure body
-LL |     closure_expecting_bound(|x: &u32| {
-   |                              - `x` is a reference that is only valid in the closure body
-LL |         f = Some(x);
-   |         ^^^^^^^^^^^ `x` escapes the closure body here
-
-error: lifetime may not live long enough
-  --> $DIR/expect-region-supply-region.rs:37:30
-   |
-LL | fn expect_bound_supply_named<'x>() {
-   |                              -- lifetime `'x` defined here
-...
-LL |     closure_expecting_bound(|x: &'x u32| {
-   |                              ^  - let's call the lifetime of this reference `'1`
-   |                              |
-   |                              requires that `'1` must outlive `'x`
-
-error: lifetime may not live long enough
-  --> $DIR/expect-region-supply-region.rs:37:30
-   |
-LL | fn expect_bound_supply_named<'x>() {
-   |                              -- lifetime `'x` defined here
-...
-LL |     closure_expecting_bound(|x: &'x u32| {
-   |                              ^ requires that `'x` must outlive `'static`
-   |
-   = help: consider replacing `'x` with `'static`
-
-error: aborting due to 4 previous errors
-
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.rs b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.rs
index 28a6ab7..55c6aa7 100644
--- a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.rs
+++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.rs
@@ -1,12 +1,14 @@
 #![allow(warnings)]
 
 fn closure_expecting_bound<F>(_: F)
-    where F: FnOnce(&u32)
+where
+    F: FnOnce(&u32),
 {
 }
 
 fn closure_expecting_free<'a, F>(_: F)
-    where F: FnOnce(&'a u32)
+where
+    F: FnOnce(&'a u32),
 {
 }
 
@@ -15,7 +17,7 @@
     // it to escape into `f`:
     let mut f: Option<&u32> = None;
     closure_expecting_bound(|x| {
-        f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
+        f = Some(x); //~ ERROR borrowed data escapes outside of closure
     });
 }
 
@@ -25,22 +27,7 @@
     // closure:
     let mut f: Option<&u32> = None;
     closure_expecting_bound(|x: &u32| {
-        f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
-    });
-}
-
-fn expect_bound_supply_named<'x>() {
-    let mut f: Option<&u32> = None;
-
-    // Here we give a type annotation that `x` should be free. We get
-    // an error because of that.
-    closure_expecting_bound(|x: &'x u32| {
-        //~^ ERROR mismatched types
-        //~| ERROR mismatched types
-
-        // And we still cannot let `x` escape into `f`.
-        f = Some(x);
-        //~^ ERROR borrowed data cannot be stored outside of its closure
+        f = Some(x); //~ ERROR borrowed data escapes outside of closure
     });
 }
 
@@ -67,4 +54,4 @@
     closure_expecting_free(|x: &'x u32| f = Some(x)); // OK
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr
index eb860f9..213071a 100644
--- a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr
+++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr
@@ -1,87 +1,22 @@
-error: borrowed data cannot be stored outside of its closure
-  --> $DIR/expect-region-supply-region.rs:18:18
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/expect-region-supply-region.rs:20:9
    |
 LL |     let mut f: Option<&u32> = None;
-   |         ----- borrowed data cannot be stored into here...
+   |         ----- `f` declared here, outside of the closure body
 LL |     closure_expecting_bound(|x| {
-   |                             --- ...because it cannot outlive this closure
+   |                              - `x` is a reference that is only valid in the closure body
 LL |         f = Some(x);
-   |                  ^ cannot be stored outside of its closure
+   |         ^^^^^^^^^^^ `x` escapes the closure body here
 
-error: borrowed data cannot be stored outside of its closure
-  --> $DIR/expect-region-supply-region.rs:28:18
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/expect-region-supply-region.rs:30:9
    |
 LL |     let mut f: Option<&u32> = None;
-   |         ----- borrowed data cannot be stored into here...
+   |         ----- `f` declared here, outside of the closure body
 LL |     closure_expecting_bound(|x: &u32| {
-   |                             --------- ...because it cannot outlive this closure
+   |                              - `x` is a reference that is only valid in the closure body
 LL |         f = Some(x);
-   |                  ^ cannot be stored outside of its closure
+   |         ^^^^^^^^^^^ `x` escapes the closure body here
 
-error[E0308]: mismatched types
-  --> $DIR/expect-region-supply-region.rs:37:33
-   |
-LL |     closure_expecting_bound(|x: &'x u32| {
-   |                                 ^^^^^^^ lifetime mismatch
-   |
-   = note: expected reference `&u32`
-              found reference `&'x u32`
-note: the anonymous lifetime #2 defined on the body at 37:29...
-  --> $DIR/expect-region-supply-region.rs:37:29
-   |
-LL |       closure_expecting_bound(|x: &'x u32| {
-   |  _____________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | |     });
-   | |_____^
-note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 32:30
-  --> $DIR/expect-region-supply-region.rs:32:30
-   |
-LL | fn expect_bound_supply_named<'x>() {
-   |                              ^^
+error: aborting due to 2 previous errors
 
-error[E0308]: mismatched types
-  --> $DIR/expect-region-supply-region.rs:37:33
-   |
-LL |     closure_expecting_bound(|x: &'x u32| {
-   |                                 ^^^^^^^ lifetime mismatch
-   |
-   = note: expected reference `&u32`
-              found reference `&'x u32`
-note: the lifetime `'x` as defined on the function body at 32:30...
-  --> $DIR/expect-region-supply-region.rs:32:30
-   |
-LL | fn expect_bound_supply_named<'x>() {
-   |                              ^^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 37:29
-  --> $DIR/expect-region-supply-region.rs:37:29
-   |
-LL |       closure_expecting_bound(|x: &'x u32| {
-   |  _____________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | |     });
-   | |_____^
-
-error: borrowed data cannot be stored outside of its closure
-  --> $DIR/expect-region-supply-region.rs:42:18
-   |
-LL |     let mut f: Option<&u32> = None;
-   |         ----- borrowed data cannot be stored into here...
-...
-LL |     closure_expecting_bound(|x: &'x u32| {
-   |                             ------------ ...because it cannot outlive this closure
-...
-LL |         f = Some(x);
-   |                  ^ cannot be stored outside of its closure
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/command/command-argv0-debug.rs b/src/test/ui/command/command-argv0-debug.rs
index 133d2ad..cb948a9 100644
--- a/src/test/ui/command/command-argv0-debug.rs
+++ b/src/test/ui/command/command-argv0-debug.rs
@@ -4,8 +4,6 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
 // ignore-sgx no processes
-#![feature(process_set_argv0)]
-
 use std::os::unix::process::CommandExt;
 use std::process::Command;
 
diff --git a/src/test/ui/command/command-argv0.rs b/src/test/ui/command/command-argv0.rs
index 56a9fb4..e3394e0 100644
--- a/src/test/ui/command/command-argv0.rs
+++ b/src/test/ui/command/command-argv0.rs
@@ -4,8 +4,6 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
 // ignore-sgx no processes
-#![feature(process_set_argv0)]
-
 use std::env;
 use std::os::unix::process::CommandExt;
 use std::process::Command;
diff --git a/src/test/ui/error-codes/E0490.nll.stderr b/src/test/ui/error-codes/E0490.nll.stderr
new file mode 100644
index 0000000..a1c33bb
--- /dev/null
+++ b/src/test/ui/error-codes/E0490.nll.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+  --> $DIR/E0490.rs:2:12
+   |
+LL | fn f<'a, 'b>(y: &'b ()) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     let x: &'a _ = &y;
+   |            ^^^^^ type annotation requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/E0490.rs:2:20
+   |
+LL | fn f<'a, 'b>(y: &'b ()) {
+   |      -- lifetime `'a` defined here
+LL |     let x: &'a _ = &y;
+   |            -----   ^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `y` is borrowed for `'a`
+...
+LL | }
+   |  - `y` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/error-codes/E0490.rs b/src/test/ui/error-codes/E0490.rs
new file mode 100644
index 0000000..36bafa2
--- /dev/null
+++ b/src/test/ui/error-codes/E0490.rs
@@ -0,0 +1,8 @@
+fn f<'a, 'b>(y: &'b ()) {
+    let x: &'a _ = &y;
+    //~^ E0490
+    //~| E0495
+    //~| E0495
+}
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0490.stderr b/src/test/ui/error-codes/E0490.stderr
new file mode 100644
index 0000000..03fce21
--- /dev/null
+++ b/src/test/ui/error-codes/E0490.stderr
@@ -0,0 +1,76 @@
+error[E0490]: a value of type `&'b ()` is borrowed for too long
+  --> $DIR/E0490.rs:2:20
+   |
+LL |     let x: &'a _ = &y;
+   |                    ^^
+   |
+note: the type is valid for the lifetime `'a` as defined on the function body at 1:6
+  --> $DIR/E0490.rs:1:6
+   |
+LL | fn f<'a, 'b>(y: &'b ()) {
+   |      ^^
+note: but the borrow lasts for the lifetime `'b` as defined on the function body at 1:10
+  --> $DIR/E0490.rs:1:10
+   |
+LL | fn f<'a, 'b>(y: &'b ()) {
+   |          ^^
+
+error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+  --> $DIR/E0490.rs:2:20
+   |
+LL |     let x: &'a _ = &y;
+   |                    ^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 1:10...
+  --> $DIR/E0490.rs:1:10
+   |
+LL | fn f<'a, 'b>(y: &'b ()) {
+   |          ^^
+note: ...so that the type `&'b ()` is not borrowed for too long
+  --> $DIR/E0490.rs:2:20
+   |
+LL |     let x: &'a _ = &y;
+   |                    ^^
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6...
+  --> $DIR/E0490.rs:1:6
+   |
+LL | fn f<'a, 'b>(y: &'b ()) {
+   |      ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/E0490.rs:2:20
+   |
+LL |     let x: &'a _ = &y;
+   |                    ^^
+
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+  --> $DIR/E0490.rs:2:20
+   |
+LL |     let x: &'a _ = &y;
+   |                    ^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 1:10...
+  --> $DIR/E0490.rs:1:10
+   |
+LL | fn f<'a, 'b>(y: &'b ()) {
+   |          ^^
+note: ...so that the expression is assignable
+  --> $DIR/E0490.rs:2:20
+   |
+LL |     let x: &'a _ = &y;
+   |                    ^^
+   = note: expected  `&'a &()`
+              found  `&'a &'b ()`
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6...
+  --> $DIR/E0490.rs:1:6
+   |
+LL | fn f<'a, 'b>(y: &'b ()) {
+   |      ^^
+note: ...so that the reference type `&'a &()` does not outlive the data it points at
+  --> $DIR/E0490.rs:2:12
+   |
+LL |     let x: &'a _ = &y;
+   |            ^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr
deleted file mode 100644
index 5140d1a..0000000
--- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/E0621-does-not-trigger-for-closures.rs:15:45
-   |
-LL |     invoke(&x, |a, b| if a > b { a } else { b });
-   |                    --                       ^ returning this value requires that `'1` must outlive `'2`
-   |                    ||
-   |                    |return type of closure is &'2 i32
-   |                    has type `&'1 i32`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.rs b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.rs
index c58744d..44f174c 100644
--- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.rs
+++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.rs
@@ -1,9 +1,7 @@
-// Test that we give the generic E0495 when one of the free regions is
+// Test that we give the generic error when one of the free regions is
 // bound in a closure (rather than suggesting a change to the signature
 // of the closure, which is not specified in `foo` but rather in `invoke`).
 
-// FIXME - This might be better as a UI test, but the finer details
-// of the error seem to vary on different machines.
 fn invoke<'a, F>(x: &'a i32, f: F) -> &'a i32
 where F: FnOnce(&'a i32, &i32) -> &'a i32
 {
@@ -12,7 +10,7 @@
 }
 
 fn foo<'a>(x: &'a i32) {
-    invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495
+    invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr
index feca7f1..b9edeb8 100644
--- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr
+++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr
@@ -1,30 +1,11 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/E0621-does-not-trigger-for-closures.rs:15:5
+error: lifetime may not live long enough
+  --> $DIR/E0621-does-not-trigger-for-closures.rs:13:45
    |
 LL |     invoke(&x, |a, b| if a > b { a } else { b });
-   |     ^^^^^^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 15:16...
-  --> $DIR/E0621-does-not-trigger-for-closures.rs:15:16
-   |
-LL |     invoke(&x, |a, b| if a > b { a } else { b });
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/E0621-does-not-trigger-for-closures.rs:15:45
-   |
-LL |     invoke(&x, |a, b| if a > b { a } else { b });
-   |                                             ^
-note: but, the lifetime must be valid for the call at 15:5...
-  --> $DIR/E0621-does-not-trigger-for-closures.rs:15:5
-   |
-LL |     invoke(&x, |a, b| if a > b { a } else { b });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...so type `&i32` of expression is valid during the expression
-  --> $DIR/E0621-does-not-trigger-for-closures.rs:15:5
-   |
-LL |     invoke(&x, |a, b| if a > b { a } else { b });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                    --                       ^ returning this value requires that `'1` must outlive `'2`
+   |                    ||
+   |                    |return type of closure is &'2 i32
+   |                    has type `&'1 i32`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
index 0faa909..9bce274 100644
--- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
@@ -1,3 +1,6 @@
+// compile-flags: -Zsave-analysis
+// This is also a regression test for #69415 and the above flag is needed.
+
 #![feature(untagged_unions)]
 
 trait Tr1 { type As1: Copy; }
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
index bfa59d8..7f2704e 100644
--- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
@@ -1,5 +1,5 @@
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:12:22
+  --> $DIR/feature-gate-associated_type_bounds.rs:15:22
    |
 LL |     type A: Iterator<Item: Copy>;
    |                      ^^^^^^^^^^
@@ -8,7 +8,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:15:22
+  --> $DIR/feature-gate-associated_type_bounds.rs:18:22
    |
 LL |     type B: Iterator<Item: 'static>;
    |                      ^^^^^^^^^^^^^
@@ -17,7 +17,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:19:20
+  --> $DIR/feature-gate-associated_type_bounds.rs:22:20
    |
 LL | struct _St1<T: Tr1<As1: Tr2>> {
    |                    ^^^^^^^^
@@ -26,7 +26,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:26:18
+  --> $DIR/feature-gate-associated_type_bounds.rs:29:18
    |
 LL | enum _En1<T: Tr1<As1: Tr2>> {
    |                  ^^^^^^^^
@@ -35,7 +35,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:33:19
+  --> $DIR/feature-gate-associated_type_bounds.rs:36:19
    |
 LL | union _Un1<T: Tr1<As1: Tr2>> {
    |                   ^^^^^^^^
@@ -44,7 +44,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:40:37
+  --> $DIR/feature-gate-associated_type_bounds.rs:43:37
    |
 LL | type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
    |                                     ^^^^^^^^^^
@@ -53,7 +53,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:43:22
+  --> $DIR/feature-gate-associated_type_bounds.rs:46:22
    |
 LL | fn _apit(_: impl Tr1<As1: Copy>) {}
    |                      ^^^^^^^^^
@@ -62,7 +62,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:45:26
+  --> $DIR/feature-gate-associated_type_bounds.rs:48:26
    |
 LL | fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
    |                          ^^^^^^^^^
@@ -71,7 +71,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:48:24
+  --> $DIR/feature-gate-associated_type_bounds.rs:51:24
    |
 LL | fn _rpit() -> impl Tr1<As1: Copy> { S1 }
    |                        ^^^^^^^^^
@@ -80,7 +80,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:51:31
+  --> $DIR/feature-gate-associated_type_bounds.rs:54:31
    |
 LL | fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
    |                               ^^^^^^^^^
@@ -89,7 +89,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:54:23
+  --> $DIR/feature-gate-associated_type_bounds.rs:57:23
    |
 LL | const _cdef: impl Tr1<As1: Copy> = S1;
    |                       ^^^^^^^^^
@@ -98,7 +98,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:60:24
+  --> $DIR/feature-gate-associated_type_bounds.rs:63:24
    |
 LL | static _sdef: impl Tr1<As1: Copy> = S1;
    |                        ^^^^^^^^^
@@ -107,7 +107,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:67:21
+  --> $DIR/feature-gate-associated_type_bounds.rs:70:21
    |
 LL |     let _: impl Tr1<As1: Copy> = S1;
    |                     ^^^^^^^^^
@@ -116,7 +116,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-associated_type_bounds.rs:54:14
+  --> $DIR/feature-gate-associated_type_bounds.rs:57:14
    |
 LL | const _cdef: impl Tr1<As1: Copy> = S1;
    |              ^^^^^^^^^^^^^^^^^^^
@@ -124,7 +124,7 @@
    = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-associated_type_bounds.rs:60:15
+  --> $DIR/feature-gate-associated_type_bounds.rs:63:15
    |
 LL | static _sdef: impl Tr1<As1: Copy> = S1;
    |               ^^^^^^^^^^^^^^^^^^^
@@ -132,7 +132,7 @@
    = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-associated_type_bounds.rs:67:12
+  --> $DIR/feature-gate-associated_type_bounds.rs:70:12
    |
 LL |     let _: impl Tr1<As1: Copy> = S1;
    |            ^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/generator/size-moved-locals.rs b/src/test/ui/generator/size-moved-locals.rs
index 74c60d9..a5786c29 100644
--- a/src/test/ui/generator/size-moved-locals.rs
+++ b/src/test/ui/generator/size-moved-locals.rs
@@ -72,6 +72,6 @@
 fn main() {
     assert_eq!(1025, std::mem::size_of_val(&move_before_yield()));
     assert_eq!(1026, std::mem::size_of_val(&move_before_yield_with_noop()));
-    assert_eq!(2051, std::mem::size_of_val(&overlap_move_points()));
+    assert_eq!(1027, std::mem::size_of_val(&overlap_move_points()));
     assert_eq!(1026, std::mem::size_of_val(&overlap_x_and_y()));
 }
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
index cd2d46a..b42ff14 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
@@ -4,17 +4,11 @@
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
    |                                                                          ^^^^^^^^^^^^^^^^^^
    |
-note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 23:1
-  --> $DIR/ordinary-bounds-unrelated.rs:23:1
+note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
+  --> $DIR/ordinary-bounds-unrelated.rs:18:74
    |
-LL | / {
-LL | |     // Hidden type `Ordinary<'0>` with constraints:
-LL | |     //
-LL | |     // ```
-...  |
-LL | |     if condition() { a } else { b }
-LL | | }
-   | |_^
+LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
+   |                                                                          ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
index 59ce93f..254643c 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
@@ -4,17 +4,11 @@
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
    |                                                              ^^^^^^^^^^^^^^^^^^
    |
-note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 22:1
-  --> $DIR/ordinary-bounds-unsuited.rs:22:1
+note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
+  --> $DIR/ordinary-bounds-unsuited.rs:20:62
    |
-LL | / {
-LL | |     // We return a value:
-LL | |     //
-LL | |     // ```
-...  |
-LL | |     if condition() { a } else { b }
-LL | | }
-   | |_^
+LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
+   |                                                              ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-72076.rs b/src/test/ui/issues/issue-72076.rs
new file mode 100644
index 0000000..1659044
--- /dev/null
+++ b/src/test/ui/issues/issue-72076.rs
@@ -0,0 +1,6 @@
+trait X {
+    type S;
+    fn f() -> Self::S {} //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-72076.stderr b/src/test/ui/issues/issue-72076.stderr
new file mode 100644
index 0000000..b942cf7
--- /dev/null
+++ b/src/test/ui/issues/issue-72076.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-72076.rs:3:23
+   |
+LL |     fn f() -> Self::S {}
+   |                       ^^ expected associated type, found `()`
+   |
+   = note: expected associated type `<Self as X>::S`
+                    found unit type `()`
+   = help: consider constraining the associated type `<Self as X>::S` to `()` or calling a method that returns `<Self as X>::S`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-72455.rs b/src/test/ui/issues/issue-72455.rs
new file mode 100644
index 0000000..b6c3bb2
--- /dev/null
+++ b/src/test/ui/issues/issue-72455.rs
@@ -0,0 +1,27 @@
+// check-pass
+
+pub trait ResultExt {
+    type Ok;
+    fn err_eprint_and_ignore(self) -> Option<Self::Ok>;
+}
+
+impl<O, E> ResultExt for std::result::Result<O, E>
+where
+    E: std::error::Error,
+{
+    type Ok = O;
+    fn err_eprint_and_ignore(self) -> Option<O>
+    where
+        Self: ,
+    {
+        match self {
+            Err(e) => {
+                eprintln!("{}", e);
+                None
+            }
+            Ok(o) => Some(o),
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs b/src/test/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs
new file mode 100644
index 0000000..e2ff9ac
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+// In PR 71930, it was discovered that the code to retrieve the inferred type of a match scrutinee
+// was incorrect.
+
+fn f() -> ! {
+    panic!()
+}
+
+fn g() -> usize {
+    match f() { // Should infer type `bool`
+        false => 0,
+        true => 1,
+    }
+}
+
+fn h() -> usize {
+    match f() { // Should infer type `!`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/break-token-spans.rs b/src/test/ui/proc-macro/break-token-spans.rs
new file mode 100644
index 0000000..59dc3b5
--- /dev/null
+++ b/src/test/ui/proc-macro/break-token-spans.rs
@@ -0,0 +1,16 @@
+// aux-build:test-macros.rs
+// Regression test for issues #68489 and #70987
+// Tests that we properly break tokens in `probably_equal_for_proc_macro`
+// See #72306
+//
+// Note that the weird spacing in this example is critical
+// for testing the issue.
+
+extern crate test_macros;
+
+#[test_macros::recollect_attr]
+fn repro() {
+    f :: < Vec < _ > > ( ) ; //~ ERROR cannot find
+    let a: Option<Option<u8>>= true; //~ ERROR mismatched
+}
+fn main() {}
diff --git a/src/test/ui/proc-macro/break-token-spans.stderr b/src/test/ui/proc-macro/break-token-spans.stderr
new file mode 100644
index 0000000..caca973
--- /dev/null
+++ b/src/test/ui/proc-macro/break-token-spans.stderr
@@ -0,0 +1,21 @@
+error[E0425]: cannot find function `f` in this scope
+  --> $DIR/break-token-spans.rs:13:5
+   |
+LL |     f :: < Vec < _ > > ( ) ;
+   |     ^ not found in this scope
+
+error[E0308]: mismatched types
+  --> $DIR/break-token-spans.rs:14:32
+   |
+LL |     let a: Option<Option<u8>>= true;
+   |            ------------------  ^^^^ expected enum `std::option::Option`, found `bool`
+   |            |
+   |            expected due to this
+   |
+   = note: expected enum `std::option::Option<std::option::Option<u8>>`
+              found type `bool`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0425.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-close-object-into-object-5.rs b/src/test/ui/regions/regions-close-object-into-object-5.rs
index 2921a2b..ff35b9a 100644
--- a/src/test/ui/regions/regions-close-object-into-object-5.rs
+++ b/src/test/ui/regions/regions-close-object-into-object-5.rs
@@ -6,22 +6,21 @@
     fn get(&self) -> T { panic!() }
 }
 
-struct B<'a, T:'a>(&'a (A<T>+'a));
+struct B<'a, T: 'a>(&'a (A<T> + 'a));
 
 trait X { fn foo(&self) {} }
 
 impl<'a, T> X for B<'a, T> {}
 
-fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
+fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
     // oh dear!
     box B(&*v) as Box<X>
-        //~^ ERROR the parameter type `T` may not live long enough
-        //~| ERROR the parameter type `T` may not live long enough
-        //~| ERROR the parameter type `T` may not live long enough
-        //~| ERROR the parameter type `T` may not live long enough
-        //~| ERROR the parameter type `T` may not live long enough
-        //~| ERROR the parameter type `T` may not live long enough
-        //~| ERROR the parameter type `T` may not live long enough
+    //~^ ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-close-object-into-object-5.stderr b/src/test/ui/regions/regions-close-object-into-object-5.stderr
index 1472700..2bcdcd1 100644
--- a/src/test/ui/regions/regions-close-object-into-object-5.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-5.stderr
@@ -1,7 +1,7 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:5
    |
-LL | fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
 LL |     box B(&*v) as Box<X>
@@ -14,24 +14,9 @@
    |     ^^^^^^^^^^
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:5
-   |
-LL | fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
-LL |     box B(&*v) as Box<X>
-   |     ^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...so that it can be closed over into an object
-  --> $DIR/regions-close-object-into-object-5.rs:17:5
-   |
-LL |     box B(&*v) as Box<X>
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:9
    |
-LL | fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
 LL |     box B(&*v) as Box<X>
@@ -46,7 +31,7 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:9
    |
-LL | fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
 LL |     box B(&*v) as Box<X>
@@ -61,7 +46,7 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:11
    |
-LL | fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
 LL |     box B(&*v) as Box<X>
@@ -76,7 +61,7 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:11
    |
-LL | fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
 LL |     box B(&*v) as Box<X>
@@ -91,7 +76,7 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:11
    |
-LL | fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
 LL |     box B(&*v) as Box<X>
@@ -103,6 +88,6 @@
 LL |     box B(&*v) as Box<X>
    |           ^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
index 7d3d51b..3101d81 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
@@ -1,5 +1,5 @@
 error[E0310]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:10:5
+  --> $DIR/regions-close-over-type-parameter-1.rs:12:5
    |
 LL |     box v as Box<dyn SomeTrait + 'static>
    |     ^^^^^
@@ -7,7 +7,7 @@
    = help: consider adding an explicit lifetime bound `A: 'static`...
 
 error[E0309]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:20:5
+  --> $DIR/regions-close-over-type-parameter-1.rs:21:5
    |
 LL |     box v as Box<dyn SomeTrait + 'b>
    |     ^^^^^
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.rs b/src/test/ui/regions/regions-close-over-type-parameter-1.rs
index 6a9aa66..6e708a5 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-1.rs
+++ b/src/test/ui/regions/regions-close-over-type-parameter-1.rs
@@ -4,22 +4,22 @@
 // an object. This should yield errors unless `A` (and the object)
 // both have suitable bounds.
 
-trait SomeTrait { fn get(&self) -> isize; }
-
-fn make_object1<A:SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
-    box v as Box<dyn SomeTrait + 'static>
-        //~^ ERROR the parameter type `A` may not live long enough
-        //~| ERROR the parameter type `A` may not live long enough
+trait SomeTrait {
+    fn get(&self) -> isize;
 }
 
-fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box<dyn SomeTrait + 'a> {
+fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
+    box v as Box<dyn SomeTrait + 'static>
+    //~^ ERROR the parameter type `A` may not live long enough
+}
+
+fn make_object2<'a, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'a> {
     box v as Box<dyn SomeTrait + 'a>
 }
 
-fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box<dyn SomeTrait + 'b> {
+fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
     box v as Box<dyn SomeTrait + 'b>
-        //~^ ERROR the parameter type `A` may not live long enough
-        //~| ERROR the parameter type `A` may not live long enough
+    //~^ ERROR the parameter type `A` may not live long enough
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr
index ed9a604..a7509cb 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr
@@ -1,60 +1,32 @@
 error[E0310]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:10:5
+  --> $DIR/regions-close-over-type-parameter-1.rs:12:5
    |
-LL | fn make_object1<A:SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
+LL | fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
    |                 -- help: consider adding an explicit lifetime bound...: `A: 'static +`
 LL |     box v as Box<dyn SomeTrait + 'static>
    |     ^^^^^
    |
 note: ...so that the type `A` will meet its required lifetime bounds
-  --> $DIR/regions-close-over-type-parameter-1.rs:10:5
+  --> $DIR/regions-close-over-type-parameter-1.rs:12:5
    |
 LL |     box v as Box<dyn SomeTrait + 'static>
    |     ^^^^^
 
-error[E0310]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:10:5
-   |
-LL | fn make_object1<A:SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
-   |                 -- help: consider adding an explicit lifetime bound...: `A: 'static +`
-LL |     box v as Box<dyn SomeTrait + 'static>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...so that it can be closed over into an object
-  --> $DIR/regions-close-over-type-parameter-1.rs:10:5
-   |
-LL |     box v as Box<dyn SomeTrait + 'static>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0309]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:20:5
+  --> $DIR/regions-close-over-type-parameter-1.rs:21:5
    |
-LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box<dyn SomeTrait + 'b> {
-   |                       -- help: consider adding an explicit lifetime bound...: `A: 'b +`
+LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
+   |                         -- help: consider adding an explicit lifetime bound...: `A: 'b +`
 LL |     box v as Box<dyn SomeTrait + 'b>
    |     ^^^^^
    |
 note: ...so that the type `A` will meet its required lifetime bounds
-  --> $DIR/regions-close-over-type-parameter-1.rs:20:5
+  --> $DIR/regions-close-over-type-parameter-1.rs:21:5
    |
 LL |     box v as Box<dyn SomeTrait + 'b>
    |     ^^^^^
 
-error[E0309]: the parameter type `A` may not live long enough
-  --> $DIR/regions-close-over-type-parameter-1.rs:20:5
-   |
-LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box<dyn SomeTrait + 'b> {
-   |                       -- help: consider adding an explicit lifetime bound...: `A: 'b +`
-LL |     box v as Box<dyn SomeTrait + 'b>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...so that it can be closed over into an object
-  --> $DIR/regions-close-over-type-parameter-1.rs:20:5
-   |
-LL |     box v as Box<dyn SomeTrait + 'b>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0309, E0310.
 For more information about an error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-escape-method.nll.stderr b/src/test/ui/regions/regions-escape-method.nll.stderr
deleted file mode 100644
index 9f42512..0000000
--- a/src/test/ui/regions/regions-escape-method.nll.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/regions-escape-method.rs:15:13
-   |
-LL |     s.f(|p| p)
-   |          -- ^ returning this value requires that `'1` must outlive `'2`
-   |          ||
-   |          |return type of closure is &'2 i32
-   |          has type `&'1 i32`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/regions/regions-escape-method.rs b/src/test/ui/regions/regions-escape-method.rs
index 5127d4d..69c01ae 100644
--- a/src/test/ui/regions/regions-escape-method.rs
+++ b/src/test/ui/regions/regions-escape-method.rs
@@ -12,5 +12,5 @@
 
 fn main() {
     let s = S;
-    s.f(|p| p) //~ ERROR cannot infer
+    s.f(|p| p) //~ ERROR lifetime may not live long enough
 }
diff --git a/src/test/ui/regions/regions-escape-method.stderr b/src/test/ui/regions/regions-escape-method.stderr
index ffc2a259..9f42512 100644
--- a/src/test/ui/regions/regions-escape-method.stderr
+++ b/src/test/ui/regions/regions-escape-method.stderr
@@ -1,32 +1,11 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+error: lifetime may not live long enough
   --> $DIR/regions-escape-method.rs:15:13
    |
 LL |     s.f(|p| p)
-   |             ^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 15:9...
-  --> $DIR/regions-escape-method.rs:15:9
-   |
-LL |     s.f(|p| p)
-   |         ^^^^^
-note: ...so that the expression is assignable
-  --> $DIR/regions-escape-method.rs:15:13
-   |
-LL |     s.f(|p| p)
-   |             ^
-   = note: expected  `&i32`
-              found  `&i32`
-note: but, the lifetime must be valid for the method call at 15:5...
-  --> $DIR/regions-escape-method.rs:15:5
-   |
-LL |     s.f(|p| p)
-   |     ^^^^^^^^^^
-note: ...so that a type/lifetime parameter is in scope here
-  --> $DIR/regions-escape-method.rs:15:5
-   |
-LL |     s.f(|p| p)
-   |     ^^^^^^^^^^
+   |          -- ^ returning this value requires that `'1` must outlive `'2`
+   |          ||
+   |          |return type of closure is &'2 i32
+   |          has type `&'1 i32`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr
deleted file mode 100644
index cae6c33..0000000
--- a/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/regions-escape-via-trait-or-not.rs:18:14
-   |
-LL |     with(|o| o)
-   |           -- ^ returning this value requires that `'1` must outlive `'2`
-   |           ||
-   |           |return type of closure is &'2 isize
-   |           has type `&'1 isize`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.rs b/src/test/ui/regions/regions-escape-via-trait-or-not.rs
index 1e08961..ac0e56d 100644
--- a/src/test/ui/regions/regions-escape-via-trait-or-not.rs
+++ b/src/test/ui/regions/regions-escape-via-trait-or-not.rs
@@ -15,7 +15,7 @@
 }
 
 fn return_it() -> isize {
-    with(|o| o) //~ ERROR cannot infer
+    with(|o| o) //~ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr
index 9082346..cae6c33 100644
--- a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr
+++ b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr
@@ -1,32 +1,11 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+error: lifetime may not live long enough
   --> $DIR/regions-escape-via-trait-or-not.rs:18:14
    |
 LL |     with(|o| o)
-   |              ^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 18:10...
-  --> $DIR/regions-escape-via-trait-or-not.rs:18:10
-   |
-LL |     with(|o| o)
-   |          ^^^^^
-note: ...so that the expression is assignable
-  --> $DIR/regions-escape-via-trait-or-not.rs:18:14
-   |
-LL |     with(|o| o)
-   |              ^
-   = note: expected  `&isize`
-              found  `&isize`
-note: but, the lifetime must be valid for the expression at 18:5...
-  --> $DIR/regions-escape-via-trait-or-not.rs:18:5
-   |
-LL |     with(|o| o)
-   |     ^^^^
-note: ...so type `fn([closure@$DIR/regions-escape-via-trait-or-not.rs:18:10: 18:15]) -> isize {with::<&isize, [closure@$DIR/regions-escape-via-trait-or-not.rs:18:10: 18:15]>}` of expression is valid during the expression
-  --> $DIR/regions-escape-via-trait-or-not.rs:18:5
-   |
-LL |     with(|o| o)
-   |     ^^^^
+   |           -- ^ returning this value requires that `'1` must outlive `'2`
+   |           ||
+   |           |return type of closure is &'2 isize
+   |           has type `&'1 isize`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-infer-call-3.nll.stderr b/src/test/ui/regions/regions-infer-call-3.nll.stderr
deleted file mode 100644
index ca51555..0000000
--- a/src/test/ui/regions/regions-infer-call-3.nll.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/regions-infer-call-3.rs:8:24
-   |
-LL |     let z = with(|y| { select(x, y) });
-   |                   --   ^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
-   |                   ||
-   |                   |return type of closure is &'2 isize
-   |                   has type `&'1 isize`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/regions/regions-infer-call-3.rs b/src/test/ui/regions/regions-infer-call-3.rs
index a76fccb..063ec84 100644
--- a/src/test/ui/regions/regions-infer-call-3.rs
+++ b/src/test/ui/regions/regions-infer-call-3.rs
@@ -6,7 +6,7 @@
 
 fn manip<'a>(x: &'a isize) -> isize {
     let z = with(|y| { select(x, y) });
-    //~^ ERROR cannot infer
+    //~^ ERROR lifetime may not live long enough
     *z
 }
 
diff --git a/src/test/ui/regions/regions-infer-call-3.stderr b/src/test/ui/regions/regions-infer-call-3.stderr
index 1d6dbdb..ca51555 100644
--- a/src/test/ui/regions/regions-infer-call-3.stderr
+++ b/src/test/ui/regions/regions-infer-call-3.stderr
@@ -1,30 +1,11 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'r in function call due to conflicting requirements
+error: lifetime may not live long enough
   --> $DIR/regions-infer-call-3.rs:8:24
    |
 LL |     let z = with(|y| { select(x, y) });
-   |                        ^^^^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 8:18...
-  --> $DIR/regions-infer-call-3.rs:8:18
-   |
-LL |     let z = with(|y| { select(x, y) });
-   |                  ^^^^^^^^^^^^^^^^^^^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/regions-infer-call-3.rs:8:34
-   |
-LL |     let z = with(|y| { select(x, y) });
-   |                                  ^
-note: but, the lifetime must be valid for the call at 8:13...
-  --> $DIR/regions-infer-call-3.rs:8:13
-   |
-LL |     let z = with(|y| { select(x, y) });
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...so type `&isize` of expression is valid during the expression
-  --> $DIR/regions-infer-call-3.rs:8:13
-   |
-LL |     let z = with(|y| { select(x, y) });
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                   --   ^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |                   ||
+   |                   |return type of closure is &'2 isize
+   |                   has type `&'1 isize`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr
deleted file mode 100644
index 4c275b1..0000000
--- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error: captured variable cannot escape `FnMut` closure body
-  --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
-   |
-LL |         let mut f = || &mut x;
-   |                      - ^^^^^^ returns a reference to a captured variable which escapes the closure body
-   |                      |
-   |                      inferred to be a `FnMut` closure
-   |
-   = note: `FnMut` closures only have access to their captured variables while they are executing...
-   = note: ...therefore, they cannot allow references to captured variables to escape
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs
index afe87f4..86e759f 100644
--- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs
+++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs
@@ -4,7 +4,7 @@
     // Unboxed closure case
     {
         let mut x = 0;
-        let mut f = || &mut x; //~ ERROR cannot infer
+        let mut f = || &mut x; //~ ERROR captured variable cannot escape `FnMut` closure body
         let x = f();
         let y = f();
     }
diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
index 946465b..4c275b1 100644
--- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
+++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
@@ -1,30 +1,13 @@
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error: captured variable cannot escape `FnMut` closure body
   --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
    |
 LL |         let mut f = || &mut x;
-   |                        ^^^^^^
+   |                      - ^^^^^^ returns a reference to a captured variable which escapes the closure body
+   |                      |
+   |                      inferred to be a `FnMut` closure
    |
-note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 7:21...
-  --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:21
-   |
-LL |         let mut f = || &mut x;
-   |                     ^^^^^^^^^
-note: ...so that closure can access `x`
-  --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
-   |
-LL |         let mut f = || &mut x;
-   |                        ^^^^^^
-note: but, the lifetime must be valid for the call at 9:17...
-  --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:9:17
-   |
-LL |         let y = f();
-   |                 ^^^
-note: ...so type `&mut i32` of expression is valid during the expression
-  --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:9:17
-   |
-LL |         let y = f();
-   |                 ^^^
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr
index 7414a7c..f7affdb 100644
--- a/src/test/ui/suggestions/into-str.stderr
+++ b/src/test/ui/suggestions/into-str.stderr
@@ -8,7 +8,6 @@
    |     ^^^ the trait `std::convert::From<std::string::String>` is not implemented for `&str`
    |
    = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix
-   = note: `std::convert::From<std::string::String>` is implemented for `&mut str`, but not for `&str`
    = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String`
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/issue-61963.rs b/src/test/ui/suggestions/issue-61963.rs
index c9d738f..666fc96 100644
--- a/src/test/ui/suggestions/issue-61963.rs
+++ b/src/test/ui/suggestions/issue-61963.rs
@@ -16,6 +16,7 @@
 
 #[dom_struct]
 pub struct Foo {
+    //~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
     qux: Qux<Qux<Baz>>,
     bar: Box<Bar>,
     //~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
diff --git a/src/test/ui/suggestions/issue-61963.stderr b/src/test/ui/suggestions/issue-61963.stderr
index 0e2eb76..62ae5fa 100644
--- a/src/test/ui/suggestions/issue-61963.stderr
+++ b/src/test/ui/suggestions/issue-61963.stderr
@@ -1,5 +1,5 @@
 error: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-61963.rs:20:14
+  --> $DIR/issue-61963.rs:21:14
    |
 LL |     bar: Box<Bar>,
    |              ^^^ help: use `dyn`: `dyn Bar`
@@ -10,5 +10,11 @@
 LL | #![deny(bare_trait_objects)]
    |         ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/issue-61963.rs:18:1
+   |
+LL | pub struct Foo {
+   | ^^^ help: use `dyn`: `dyn pub`
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.rs b/src/test/ui/suggestions/issue-71394-no-from-impl.rs
new file mode 100644
index 0000000..9ffcc3f
--- /dev/null
+++ b/src/test/ui/suggestions/issue-71394-no-from-impl.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let data: &[u8] = &[0; 10];
+    let _: &[i8] = data.into();
+    //~^ ERROR the trait bound `&[i8]: std::convert::From<&[u8]>` is not satisfied
+}
diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr
new file mode 100644
index 0000000..84c73c2
--- /dev/null
+++ b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr
@@ -0,0 +1,11 @@
+error[E0277]: the trait bound `&[i8]: std::convert::From<&[u8]>` is not satisfied
+  --> $DIR/issue-71394-no-from-impl.rs:3:25
+   |
+LL |     let _: &[i8] = data.into();
+   |                         ^^^^ the trait `std::convert::From<&[u8]>` is not implemented for `&[i8]`
+   |
+   = note: required because of the requirements on the impl of `std::convert::Into<&[i8]>` for `&[u8]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs
index 7465049..0d90e44 100644
--- a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs
+++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs
@@ -7,6 +7,7 @@
 
     fn func(&self) -> Self::A;
     fn funk(&self, _: Self::A);
+    fn funq(&self) -> Self::A {} //~ ERROR mismatched types
 }
 
 fn foo(_: impl Trait, x: impl Trait) {
diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr
index 5ae1d45..e629f8f 100644
--- a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr
+++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr
@@ -1,5 +1,19 @@
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:13:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:10:31
+   |
+LL |     fn funq(&self) -> Self::A {}
+   |                               ^^ expected associated type, found `()`
+   |
+   = note: expected associated type `<Self as Trait<T>>::A`
+                    found unit type `()`
+help: a method is available that returns `<Self as Trait<T>>::A`
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:8:5
+   |
+LL |     fn func(&self) -> Self::A;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func`
+
+error[E0308]: mismatched types
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:14:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found associated type
@@ -12,7 +26,7 @@
    |                                    ^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:17:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:18:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found associated type
@@ -25,7 +39,7 @@
    |                ^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:21:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:22:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found associated type
@@ -38,25 +52,28 @@
    |                          ^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:25:12
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:26:12
    |
 LL |     x.funk(3);
    |            ^ expected associated type, found integer
    |
    = note: expected associated type `<T as Trait<i32>>::A`
                          found type `{integer}`
-help: a method is available that returns `<T as Trait<i32>>::A`
+help: some methods are available that return `<T as Trait<i32>>::A`
   --> $DIR/trait-with-missing-associated-type-restriction.rs:8:5
    |
 LL |     fn func(&self) -> Self::A;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func`
+LL |     fn funk(&self, _: Self::A);
+LL |     fn funq(&self) -> Self::A {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::funq`
 help: consider constraining the associated type `<T as Trait<i32>>::A` to `{integer}`
    |
 LL | fn bar2<T: Trait<i32, A = {integer}>>(x: T) {
    |                     ^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:26:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:27:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found associated type
@@ -69,7 +86,7 @@
    |                     ^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:30:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:31:9
    |
 LL | fn baz<D: std::fmt::Debug, T: Trait<A = D>>(x: T) {
    |        - this type parameter
@@ -80,13 +97,13 @@
            found type parameter `D`
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:34:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:35:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found `()`
 
 error[E0308]: mismatched types
-  --> $DIR/trait-with-missing-associated-type-restriction.rs:38:9
+  --> $DIR/trait-with-missing-associated-type-restriction.rs:39:9
    |
 LL |     qux(x.func())
    |         ^^^^^^^^ expected `usize`, found associated type
@@ -98,6 +115,6 @@
 LL | fn ban<T>(x: T) where T: Trait<A = usize> {
    |                               ^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs
index 1f689a5..cdcf89e 100644
--- a/src/test/ui/symbol-names/impl1.rs
+++ b/src/test/ui/symbol-names/impl1.rs
@@ -3,8 +3,8 @@
 // revisions: legacy v0
 //[legacy]compile-flags: -Z symbol-mangling-version=legacy
     //[v0]compile-flags: -Z symbol-mangling-version=v0
-//[legacy]normalize-stderr-32bit: "hdb62078998ce7ea8" -> "SYMBOL_HASH"
-//[legacy]normalize-stderr-64bit: "h62e540f14f879d56" -> "SYMBOL_HASH"
+//[legacy]normalize-stderr-32bit: "h5ef5dfc14aeecbfc" -> "SYMBOL_HASH"
+//[legacy]normalize-stderr-64bit: "h9e54d216f70fcbc5" -> "SYMBOL_HASH"
 
 #![feature(optin_builtin_traits, rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/test/ui/traits/traits-issue-71136.rs b/src/test/ui/traits/traits-issue-71136.rs
new file mode 100644
index 0000000..b21756e
--- /dev/null
+++ b/src/test/ui/traits/traits-issue-71136.rs
@@ -0,0 +1,8 @@
+struct Foo(u8);
+
+#[derive(Clone)]
+struct FooHolster {
+    the_foos: Vec<Foo>, //~ERROR Clone
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/traits-issue-71136.stderr b/src/test/ui/traits/traits-issue-71136.stderr
new file mode 100644
index 0000000..4c0a430
--- /dev/null
+++ b/src/test/ui/traits/traits-issue-71136.stderr
@@ -0,0 +1,13 @@
+error[E0277]: the trait bound `Foo: std::clone::Clone` is not satisfied
+  --> $DIR/traits-issue-71136.rs:5:5
+   |
+LL |     the_foos: Vec<Foo>,
+   |     ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `std::clone::Clone`
+   |
+   = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<Foo>`
+   = note: required by `std::clone::Clone::clone`
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 704a95e..0a02aa7 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -3,7 +3,7 @@
 use rustc_hir::{Body, FnDecl, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{Opaque, Predicate::Trait, ToPolyTraitRef};
+use rustc_middle::ty::{Opaque, PredicateKind::Trait, ToPolyTraitRef};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt;
@@ -91,7 +91,7 @@
                             cx.tcx.infer_ctxt().enter(|infcx| {
                                 for FulfillmentError { obligation, .. } in send_errors {
                                     infcx.maybe_note_obligation_cause_for_async_await(db, &obligation);
-                                    if let Trait(trait_pred, _) = obligation.predicate {
+                                    if let Trait(trait_pred, _) = obligation.predicate.kind() {
                                         let trait_ref = trait_pred.to_poly_trait_ref();
                                         db.note(&*format!(
                                             "`{}` doesn't implement `{}`",
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 626427c..810a226 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -18,7 +18,7 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Predicate, Ty};
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{sym, SymbolStr};
@@ -1496,8 +1496,8 @@
             if let ty::Opaque(def_id, _) = ret_ty.kind {
                 // one of the associated types must be Self
                 for predicate in cx.tcx.predicates_of(def_id).predicates {
-                    match predicate {
-                        (Predicate::Projection(poly_projection_predicate), _) => {
+                    match predicate.0.kind() {
+                        ty::PredicateKind::Projection(poly_projection_predicate) => {
                             let binder = poly_projection_predicate.ty();
                             let associated_type = binder.skip_binder();
 
@@ -1506,7 +1506,7 @@
                                 return;
                             }
                         },
-                        (_, _) => {},
+                        _ => {},
                     }
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 5300fd2..3ad3d5a 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -71,7 +71,7 @@
 fn is_executable(cx: &LateContext<'_, '_>) -> bool {
     use rustc_session::config::CrateType;
 
-    cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| match t {
+    cx.tcx.sess.crate_types().iter().any(|t: &CrateType| match t {
         CrateType::Executable => true,
         _ => false,
     })
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index ed48ab5..60c5360 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -114,7 +114,7 @@
         let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter().copied())
             .filter(|p| !p.is_global())
             .filter_map(|obligation| {
-                if let ty::Predicate::Trait(poly_trait_ref, _) = obligation.predicate {
+                if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate.kind() {
                     if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars()
                     {
                         return None;
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 438a9f4..f224732 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -1299,7 +1299,7 @@
         ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
         ty::Opaque(ref def_id, _) => {
             for (predicate, _) in cx.tcx.predicates_of(*def_id).predicates {
-                if let ty::Predicate::Trait(ref poly_trait_predicate, _) = predicate {
+                if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = predicate.kind() {
                     if must_use_attr(&cx.tcx.get_attrs(poly_trait_predicate.skip_binder().trait_ref.def_id)).is_some() {
                         return true;
                     }
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 988a226..72437e0 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -39,6 +39,19 @@
     'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'},
 }
 
+LABELS = {
+    'miri': ['A-miri', 'C-bug'],
+    'rls': ['A-rls', 'C-bug'],
+    'rustfmt': ['C-bug'],
+    'book': ['C-bug'],
+    'nomicon': ['C-bug'],
+    'reference': ['C-bug'],
+    'rust-by-example': ['C-bug'],
+    'embedded-book': ['C-bug'],
+    'edition-guide': ['C-bug'],
+    'rustc-dev-guide': ['C-bug'],
+}
+
 REPOS = {
     'miri': 'https://github.com/rust-lang/miri',
     'rls': 'https://github.com/rust-lang/rls',
@@ -132,6 +145,7 @@
     assignees,
     relevant_pr_number,
     relevant_pr_user,
+    labels,
 ):
     # Open an issue about the toolstate failure.
     if status == 'test-fail':
@@ -155,6 +169,7 @@
         )),
         'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number),
         'assignees': list(assignees),
+        'labels': labels,
     })
     print("Creating issue:\n{}".format(request))
     response = urllib2.urlopen(urllib2.Request(
@@ -235,7 +250,7 @@
                 try:
                     issue(
                         tool, create_issue_for_status, MAINTAINERS.get(tool, ''),
-                        relevant_pr_number, relevant_pr_user,
+                        relevant_pr_number, relevant_pr_user, LABELS.get(tool, ''),
                     )
                 except urllib2.HTTPError as e:
                     # network errors will simply end up not creating an issue, but that's better
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index d3c7b7a..6138902 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -128,6 +128,7 @@
     "miniz_oxide",
     "nodrop",
     "num_cpus",
+    "once_cell",
     "opaque-debug",
     "parking_lot",
     "parking_lot_core",
diff --git a/triagebot.toml b/triagebot.toml
index 2210a8f..f12d516 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -37,5 +37,9 @@
 [prioritize]
 label = "I-prioritize"
 prioritize_on = ["regression-from-stable-to-stable", "regression-from-stable-to-beta", "regression-from-stable-to-nightly"]
-priority_labels = "P-*"
+exclude_labels = [
+    "P-*",
+    "T-infra",
+    "T-release",
+]
 zulip_stream = 227806